TB2J 0.9.9rc4__tar.gz → 0.9.9rc6__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 (101) hide show
  1. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/PKG-INFO +1 -1
  2. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/MAE.py +3 -3
  3. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/MAEGreen.py +43 -11
  4. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/contour.py +16 -0
  5. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/exchange.py +30 -27
  6. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/exchangeCL2.py +20 -11
  7. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/exchange_params.py +19 -4
  8. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/green.py +77 -14
  9. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/siesta_interface.py +2 -1
  10. tb2j-0.9.9rc6/TB2J/kpoints.py +101 -0
  11. tb2j-0.9.9rc6/TB2J/mycfr.py +114 -0
  12. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/orbmap.py +4 -4
  13. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/symmetrize_J.py +17 -7
  14. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/versioninfo.py +2 -1
  15. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/PKG-INFO +1 -1
  16. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/SOURCES.txt +1 -0
  17. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/setup.py +1 -1
  18. tb2j-0.9.9rc4/TB2J/kpoints.py +0 -16
  19. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/LICENSE +0 -0
  20. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/README.md +0 -0
  21. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/Jdownfolder.py +0 -0
  22. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/Jtensor.py +0 -0
  23. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/Oiju.py +0 -0
  24. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/Oiju_epc.py +0 -0
  25. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/__init__.py +0 -0
  26. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/anisotropy.py +0 -0
  27. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/basis.py +0 -0
  28. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/citation.py +0 -0
  29. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/density_matrix.py +0 -0
  30. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/epc.py +0 -0
  31. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/exchange_pert.py +0 -0
  32. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/exchange_qspace.py +0 -0
  33. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/external/__init__.py +0 -0
  34. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/external/p_tqdm.py +0 -0
  35. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/gpaw_wrapper.py +0 -0
  36. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/greentest.py +0 -0
  37. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/__init__.py +0 -0
  38. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/__init__.py +0 -0
  39. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/abacus_api.py +0 -0
  40. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/abacus_wrapper.py +0 -0
  41. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/gen_exchange_abacus.py +0 -0
  42. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/orbital_api.py +0 -0
  43. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/stru_api.py +0 -0
  44. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/test_density_matrix.py +0 -0
  45. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/test_read_HRSR.py +0 -0
  46. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/abacus/test_read_stru.py +0 -0
  47. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/gpaw_interface.py +0 -0
  48. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/lawaf_interface.py +0 -0
  49. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/manager.py +0 -0
  50. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/interfaces/wannier90_interface.py +0 -0
  51. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/__init__.py +0 -0
  52. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_exchange.py +0 -0
  53. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_multibinit.py +0 -0
  54. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_tomsasd.py +0 -0
  55. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_txt.py +0 -0
  56. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_uppasd.py +0 -0
  57. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_exchange/io_vampire.py +0 -0
  58. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/io_merge.py +0 -0
  59. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/mathutils/__init__.py +0 -0
  60. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/mathutils/fermi.py +0 -0
  61. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/mathutils/kR_convert.py +0 -0
  62. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/mathutils/lowdin.py +0 -0
  63. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/mathutils/rotate_spin.py +0 -0
  64. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/myTB.py +0 -0
  65. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/pauli.py +0 -0
  66. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/pert.py +0 -0
  67. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/plot.py +0 -0
  68. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/rotate_atoms.py +0 -0
  69. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/rotate_siestaDM.py +0 -0
  70. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/sisl_wrapper.py +0 -0
  71. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/__init__.py +0 -0
  72. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/base_parser.py +0 -0
  73. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/constants.py +0 -0
  74. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/hamiltonian.py +0 -0
  75. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/hamiltonian_terms.py +0 -0
  76. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/plot.py +0 -0
  77. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/qsolver.py +0 -0
  78. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/spin_api.py +0 -0
  79. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/spin_xml.py +0 -0
  80. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/spinham/supercell.py +0 -0
  81. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/tensor_rotate.py +0 -0
  82. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/utest.py +0 -0
  83. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/utils.py +0 -0
  84. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/wannier/__init__.py +0 -0
  85. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/wannier/w90_parser.py +0 -0
  86. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J/wannier/w90_tb_parser.py +0 -0
  87. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/dependency_links.txt +0 -0
  88. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/entry_points.txt +0 -0
  89. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/requires.txt +0 -0
  90. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/TB2J.egg-info/top_level.txt +0 -0
  91. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_downfold.py +0 -0
  92. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_eigen.py +0 -0
  93. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_magnon.py +0 -0
  94. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_magnon_dos.py +0 -0
  95. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_merge.py +0 -0
  96. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_rotate.py +0 -0
  97. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/TB2J_rotateDM.py +0 -0
  98. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/abacus2J.py +0 -0
  99. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/siesta2J.py +0 -0
  100. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/scripts/wann2J.py +0 -0
  101. {tb2j-0.9.9rc4 → tb2j-0.9.9rc6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.9.9rc4
3
+ Version: 0.9.9rc6
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
@@ -137,9 +137,9 @@ class MAEGreen(MAE):
137
137
  efermi = occ.efermi(evals)
138
138
  print(f"{efermi=}")
139
139
  self.G = TBGreen(model, kmesh, efermi=efermi, gamma=gamma, **kwargs)
140
- self.emin = -12
140
+ self.emin = -52
141
141
  self.emax = 0
142
- self.nz = 50
142
+ self.nz = 100
143
143
  self._prepare_elist()
144
144
 
145
145
  def _prepare_elist(self, method="legendre"):
@@ -186,7 +186,7 @@ class MAEGreen(MAE):
186
186
  for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
187
187
  dE_angle = self.get_perturbed(e, thetas, phis)
188
188
  es += np.imag(dE_angle * self.contour.weights[ie])
189
- return -es / np.pi
189
+ return -es / np.pi / 2
190
190
 
191
191
 
192
192
  def get_model_energy(model, kmesh, gamma=True):
@@ -3,10 +3,11 @@ from pathlib import Path
3
3
  import numpy as np
4
4
  import tqdm
5
5
  from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
6
- from HamiltonIO.model.occupations import Occupations
6
+ from HamiltonIO.model.occupations import GaussOccupations
7
7
  from typing_extensions import DefaultDict
8
8
 
9
9
  from TB2J.exchange import ExchangeNCL
10
+ from TB2J.external import p_map
10
11
 
11
12
  # from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
12
13
  # from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
@@ -16,7 +17,7 @@ from TB2J.mathutils.rotate_spin import (
16
17
 
17
18
 
18
19
  def get_occupation(evals, kweights, nel, width=0.1):
19
- occ = Occupations(nel=nel, width=width, wk=kweights, nspin=2)
20
+ occ = GaussOccupations(nel=nel, width=width, wk=kweights, nspin=2)
20
21
  return occ.occupy(evals)
21
22
 
22
23
 
@@ -78,6 +79,17 @@ class MAEGreen(ExchangeNCL):
78
79
 
79
80
  def get_perturbed(self, e, thetas, phis):
80
81
  self.tbmodel.set_so_strength(0.0)
82
+ maxsoc = self.tbmodel.get_max_Hsoc_abs()
83
+ maxH0 = self.tbmodel.get_max_H0_spin_abs()
84
+ if maxsoc > maxH0 * 0.01:
85
+ print(f"""Warning: The SOC of the Hamiltonian has a maximum of {maxsoc} eV,
86
+ comparing to the maximum of {maxH0} eV of the spin part of the Hamiltonian.
87
+ The SOC is too strong, the perturbation theory may not be valid.""")
88
+
89
+ print(f"""Warning: The SOC of the Hamiltonian has a maximum of {maxsoc} eV,
90
+ comparing to the maximum of {maxH0} eV of the spin part of the Hamiltonian.
91
+ The SOC is too strong, the perturbation theory may not be valid.""")
92
+
81
93
  G0K = self.G.get_Gk_all(e)
82
94
  Hsoc_k = self.tbmodel.get_Hk_soc(self.G.kpts)
83
95
  na = len(thetas)
@@ -97,6 +109,7 @@ class MAEGreen(ExchangeNCL):
97
109
  dG2 = GdH * GdH.T
98
110
  dG2sum = np.sum(dG2)
99
111
  # print(f"dG2sum-sum: {dG2sum}")
112
+ dG2sum = np.sum(dG2diag)
100
113
 
101
114
  # dG2sum = np.trace(GdH @ GdH)
102
115
  # print(f"dG2sum-Tr: {dG2sum}")
@@ -142,15 +155,33 @@ class MAEGreen(ExchangeNCL):
142
155
  if with_eigen:
143
156
  self.es2 = self.get_band_energy_vs_angles_from_eigen(thetas, phis)
144
157
 
145
- for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
146
- dE_angle, dE_angle_atom, dE_angle_atom_orb = self.get_perturbed(
147
- e, thetas, phis
148
- )
149
- self.es += dE_angle * self.contour.weights[ie]
150
- self.es_atom += dE_angle_atom * self.contour.weights[ie]
158
+ # for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
159
+ # dE_angle, dE_angle_atom, dE_angle_atom_orb = self.get_perturbed(
160
+ # e, thetas, phis
161
+ # )
162
+ # self.es += dE_angle * self.contour.weights[ie]
163
+ # self.es_atom += dE_angle_atom * self.contour.weights[ie]
164
+ # for key, value in dE_angle_atom_orb.items():
165
+ # self.es_atom_orb[key] += (
166
+ # dE_angle_atom_orb[key] * self.contour.weights[ie]
167
+ # )
168
+
169
+ # rewrite the for loop above to use p_map
170
+ def func(e):
171
+ return self.get_perturbed(e, thetas, phis)
172
+
173
+ if self.nproc > 1:
174
+ results = p_map(func, self.contour.path, num_cpus=self.nproc)
175
+ else:
176
+ npole = len(self.contour.path)
177
+ results = map(func, tqdm.tqdm(self.contour.path, total=npole))
178
+ for i, result in enumerate(results):
179
+ dE_angle, dE_angle_atom, dE_angle_atom_orb = result
180
+ self.es += dE_angle * self.contour.weights[i]
181
+ self.es_atom += dE_angle_atom * self.contour.weights[i]
151
182
  for key, value in dE_angle_atom_orb.items():
152
183
  self.es_atom_orb[key] += (
153
- dE_angle_atom_orb[key] * self.contour.weights[ie]
184
+ dE_angle_atom_orb[key] * self.contour.weights[i]
154
185
  )
155
186
 
156
187
  self.es = -np.imag(self.es) / (2 * np.pi)
@@ -158,7 +189,7 @@ class MAEGreen(ExchangeNCL):
158
189
  for key, value in self.es_atom_orb.items():
159
190
  self.es_atom_orb[key] = -np.imag(value) / (2 * np.pi)
160
191
 
161
- def output(self, output_path="TB2J_anisotropy", with_eigen=False):
192
+ def output(self, output_path="TB2J_anisotropy", with_eigen=True):
162
193
  Path(output_path).mkdir(exist_ok=True)
163
194
  fname = f"{output_path}/MAE.dat"
164
195
  fname_orb = f"{output_path}/MAE_orb.dat"
@@ -242,6 +273,7 @@ def abacus_get_MAE(
242
273
  magnetic_elements=None,
243
274
  nel=None,
244
275
  width=0.1,
276
+ with_eigen=False,
245
277
  **kwargs,
246
278
  ):
247
279
  """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."""
@@ -262,4 +294,4 @@ def abacus_get_MAE(
262
294
  magnetic_elements=magnetic_elements,
263
295
  **kwargs,
264
296
  )
265
- mae.run(output_path=output_path)
297
+ mae.run(output_path=output_path, with_eigen=with_eigen)
@@ -1,5 +1,6 @@
1
1
  import numpy as np
2
2
  from scipy.special import roots_legendre
3
+
3
4
  from TB2J.utils import simpson_nonuniform_weight
4
5
 
5
6
 
@@ -15,6 +16,21 @@ class Contour:
15
16
  self._weights = simpson_nonuniform_weight(self.path)
16
17
  return self._weights
17
18
 
19
+ def integrate_func(self, func):
20
+ """
21
+ integrate f along the path
22
+ """
23
+ return np.dot(func(self.path), self.weights)
24
+
25
+ def integrate_values(self, values):
26
+ """
27
+ integrate f along the path
28
+ """
29
+ ret = 0
30
+ for i in range(len(values)):
31
+ ret += values[i] * self.weights[i]
32
+ return ret
33
+
18
34
  def build_path_semicircle(self, npoints, endpoint=True):
19
35
  R = (self.emax - self.emin) / 2.0
20
36
  R0 = (self.emin + self.emax) / 2.0
@@ -10,29 +10,24 @@ from TB2J.exchange_params import ExchangeParams
10
10
  from TB2J.external import p_map
11
11
  from TB2J.green import TBGreen
12
12
  from TB2J.io_exchange import SpinIO
13
+ from TB2J.mycfr import CFR
13
14
  from TB2J.orbmap import map_orbs_matrix
14
15
  from TB2J.pauli import pauli_block_all, pauli_block_sigma_norm
15
16
  from TB2J.utils import (
16
17
  kmesh_to_R,
17
- simpson_nonuniform,
18
18
  symbol_number,
19
- trapezoidal_nonuniform,
20
19
  )
21
20
 
22
21
 
23
22
  class Exchange(ExchangeParams):
24
- def __init__(
25
- self,
26
- tbmodels,
27
- atoms,
28
- **params: ExchangeParams,
29
- ):
23
+ def __init__(self, tbmodels, atoms, **params):
30
24
  self.atoms = atoms
31
25
  super().__init__(**params)
32
26
  self._prepare_kmesh(self._kmesh)
33
27
  self._prepare_Rlist()
34
28
  self.set_tbmodels(tbmodels)
35
29
  self._adjust_emin()
30
+ # self._prepare_elist(method="CFR")
36
31
  self._prepare_elist(method="legendre")
37
32
  self._prepare_basis()
38
33
  self._prepare_orb_dict()
@@ -50,8 +45,9 @@ class Exchange(ExchangeParams):
50
45
  os.makedirs(self.orbpath, exist_ok=True)
51
46
 
52
47
  def _adjust_emin(self):
53
- # self.emin = self.G.find_energy_ingap(rbound=self.efermi - 10.0) - self.efermi
54
- self.emin = -22.0
48
+ self.emin = self.G.find_energy_ingap(rbound=self.efermi - 15.0) - self.efermi
49
+ # self.emin = self.G.find_energy_ingap(rbound=self.efermi - 15.0) - self.efermi
50
+ # self.emin = -42.0
55
51
  print(f"A gap is found at {self.emin}, set emin to it.")
56
52
 
57
53
  def set_tbmodels(self, tbmodels):
@@ -62,25 +58,28 @@ class Exchange(ExchangeParams):
62
58
  # del self.G.tbmodel
63
59
  pass
64
60
 
65
- def _prepare_kmesh(self, kmesh):
61
+ def _prepare_kmesh(self, kmesh, ibz=False):
66
62
  for k in kmesh:
67
63
  self.kmesh = list(map(lambda x: x // 2 * 2 + 1, kmesh))
68
64
 
69
- def _prepare_elist(self, method="legendre"):
65
+ def _prepare_elist(self, method="CFR"):
70
66
  """
71
67
  prepare list of energy for integration.
72
68
  The path has three segments:
73
69
  emin --1-> emin + 1j*height --2-> emax+1j*height --3-> emax
74
70
  """
75
- self.contour = Contour(self.emin, self.emax)
76
71
  # if method.lower() == "rectangle":
77
72
  # self.contour.build_path_rectangle(
78
73
  # height=self.height, nz1=self.nz1, nz2=self.nz2, nz3=self.nz3
79
74
  # )
80
75
  if method.lower() == "semicircle":
76
+ self.contour = Contour(self.emin, self.emax)
81
77
  self.contour.build_path_semicircle(npoints=self.nz, endpoint=True)
82
78
  elif method.lower() == "legendre":
79
+ self.contour = Contour(self.emin, self.emax)
83
80
  self.contour.build_path_legendre(npoints=self.nz, endpoint=True)
81
+ elif method.lower() == "cfr":
82
+ self.contour = CFR(nz=self.nz, T=600)
84
83
  else:
85
84
  raise ValueError(f"The path cannot be of type {method}.")
86
85
 
@@ -119,6 +118,7 @@ class Exchange(ExchangeParams):
119
118
  else:
120
119
  try:
121
120
  atom_sym, orb_sym = base[:2]
121
+ iatom = sdict[atom_sym]
122
122
  except Exception:
123
123
  iatom = base.iatom
124
124
  atom_sym = base.iatom
@@ -150,7 +150,7 @@ class Exchange(ExchangeParams):
150
150
  )
151
151
  if not self._is_collinear:
152
152
  for iatom, orb in self.orb_dict.items():
153
- print(f"iatom: {iatom}, orb: {orb}")
153
+ # print(f"iatom: {iatom}, orb: {orb}")
154
154
  nsorb = len(self.orb_dict[iatom])
155
155
  if nsorb % 2 != 0 and False:
156
156
  raise ValueError(
@@ -173,10 +173,9 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
173
173
  self.mmats = {}
174
174
  self.orbital_names = {}
175
175
  self.norb_reduced = {}
176
- print(f"self.backend_name: {self.backend_name}")
177
176
  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}")
177
+ # print(f"magntic_elements: {self.magnetic_elements}")
178
+ # print(f"include_orbs: {self.include_orbs}")
180
179
  syms = self.atoms.get_chemical_symbols()
181
180
  for iatom, orbs in self.labels.items():
182
181
  if (self.include_orbs is not None) and syms[iatom] in self.include_orbs:
@@ -186,7 +185,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
186
185
  include_only=self.include_orbs[syms[iatom]],
187
186
  )
188
187
  else:
189
- print(f"orbs: {orbs}")
188
+ # print(f"orbs: {orbs}")
190
189
  mmat, reduced_orbs = map_orbs_matrix(
191
190
  orbs, spinor=not (self._is_collinear), include_only=None
192
191
  )
@@ -271,10 +270,10 @@ class ExchangeNCL(Exchange):
271
270
  """
272
271
  self.tbmodel = tbmodels
273
272
  self.backend_name = self.tbmodel.name
274
- print(self.kmesh)
275
273
  self.G = TBGreen(
276
274
  tbmodel=self.tbmodel,
277
275
  kmesh=self.kmesh,
276
+ ibz=self.ibz,
278
277
  gamma=True,
279
278
  efermi=self.efermi,
280
279
  use_cache=self._use_cache,
@@ -567,20 +566,24 @@ class ExchangeNCL(Exchange):
567
566
  AijRs: a list of AijR,
568
567
  wherer AijR: array of ((nR, n, n, 4,4), dtype=complex)
569
568
  """
570
- if method == "trapezoidal":
571
- integrate = trapezoidal_nonuniform
572
- elif method == "simpson":
573
- integrate = simpson_nonuniform
569
+ # if method == "trapezoidal":
570
+ # integrate = trapezoidal_nonuniform
571
+ # elif method == "simpson":
572
+ # integrate = simpson_nonuniform
573
+ #
574
574
 
575
575
  # self.rho = integrate(self.contour.path, rhoRs)
576
576
  for iR, R in enumerate(self.R_ijatom_dict):
577
577
  for iatom, jatom in self.R_ijatom_dict[R]:
578
578
  f = AijRs[(R, iatom, jatom)]
579
- self.A_ijR[(R, iatom, jatom)] = integrate(self.contour.path, f)
579
+ # self.A_ijR[(R, iatom, jatom)] = integrate(self.contour.path, f)
580
+ self.A_ijR[(R, iatom, jatom)] = self.contour.integrate_values(f)
581
+
580
582
  if self.orb_decomposition:
581
- self.A_ijR_orb[(R, iatom, jatom)] = integrate(
582
- self.contour.path, AijRs_orb[(R, iatom, jatom)]
583
- )
583
+ # self.A_ijR_orb[(R, iatom, jatom)] = integrate(
584
+ # self.contour.path, AijRs_orb[(R, iatom, jatom)]
585
+ # )
586
+ self.contour.integrate_values(AijRs_orb[(R, iatom, jatom)])
584
587
 
585
588
  def get_quantities_per_e(self, e):
586
589
  Gk_all = self.G.get_Gk_all(e)
@@ -1,15 +1,18 @@
1
1
  """
2
2
  Exchange from Green's function
3
3
  """
4
+
4
5
  import os
5
6
  from collections import defaultdict
7
+
6
8
  import numpy as np
7
- from TB2J.green import TBGreen
8
- from TB2J.io_exchange import SpinIO
9
9
  from tqdm import tqdm
10
+
10
11
  from TB2J.external import p_map
12
+ from TB2J.green import TBGreen
13
+ from TB2J.io_exchange import SpinIO
14
+
11
15
  from .exchange import ExchangeCL
12
- from .utils import simpson_nonuniform, trapezoidal_nonuniform
13
16
 
14
17
 
15
18
  class ExchangeCL2(ExchangeCL):
@@ -221,17 +224,23 @@ class ExchangeCL2(ExchangeCL):
221
224
  # shutil.rmtree(path)
222
225
 
223
226
  def integrate(self, method="simpson"):
224
- if method == "trapezoidal":
225
- integrate = trapezoidal_nonuniform
226
- elif method == "simpson":
227
- integrate = simpson_nonuniform
227
+ # if method == "trapezoidal":
228
+ # integrate = trapezoidal_nonuniform
229
+ # elif method == "simpson":
230
+ # integrate = simpson_nonuniform
228
231
  for R, ijpairs in self.R_ijatom_dict.items():
229
232
  for iatom, jatom in ijpairs:
230
- self.Jorb[(R, iatom, jatom)] = integrate(
231
- self.contour.path, self.Jorb_list[(R, iatom, jatom)]
233
+ # self.Jorb[(R, iatom, jatom)] = integrate(
234
+ # self.contour.path, self.Jorb_list[(R, iatom, jatom)]
235
+ # )
236
+ # self.JJ[(R, iatom, jatom)] = integrate(
237
+ # self.contour.path, self.JJ_list[(R, iatom, jatom)]
238
+ # )
239
+ self.Jorb[(R, iatom, jatom)] = self.contour.integrate_values(
240
+ self.Jorb_list[(R, iatom, jatom)]
232
241
  )
233
- self.JJ[(R, iatom, jatom)] = integrate(
234
- self.contour.path, self.JJ_list[(R, iatom, jatom)]
242
+ self.JJ[(R, iatom, jatom)] = self.contour.integrate_values(
243
+ self.JJ_list[(R, iatom, jatom)]
235
244
  )
236
245
 
237
246
  def get_quantities_per_e(self, e):
@@ -31,6 +31,7 @@ class ExchangeParams:
31
31
  output_path: str = "TB2J_results"
32
32
  mae_angles = None
33
33
  orth = False
34
+ ibz = False
34
35
 
35
36
  def __init__(
36
37
  self,
@@ -53,6 +54,7 @@ class ExchangeParams:
53
54
  exclude_orbs=[],
54
55
  mae_angles=None,
55
56
  orth=False,
57
+ ibz=False,
56
58
  ):
57
59
  self.efermi = efermi
58
60
  self.basis = basis
@@ -76,6 +78,7 @@ class ExchangeParams:
76
78
  self.output_path = output_path
77
79
  self.mae_angles = mae_angles
78
80
  self.orth = orth
81
+ self.ibz = ibz
79
82
 
80
83
  def set_params(self, **kwargs):
81
84
  for key, val in kwargs.items():
@@ -92,8 +95,6 @@ class ExchangeParams:
92
95
  include_orbs = {}
93
96
  if isinstance(magnetic_elements, str):
94
97
  magnetic_elements = [magnetic_elements]
95
- print(f"magnetic_elements: {magnetic_elements}")
96
- print(f"include_orbs: {include_orbs}")
97
98
  for element in magnetic_elements:
98
99
  if "_" in element:
99
100
  elem = element.split("_")[0]
@@ -102,8 +103,6 @@ class ExchangeParams:
102
103
  else:
103
104
  include_orbs[element] = None
104
105
 
105
- print(f"magnetic_elements: {magnetic_elements}")
106
- print(f"include_orbs: {include_orbs}")
107
106
  magnetic_elements = list(include_orbs.keys())
108
107
  return magnetic_elements, include_orbs
109
108
 
@@ -116,6 +115,14 @@ def add_exchange_args_to_parser(parser: argparse.ArgumentParser):
116
115
  type=str,
117
116
  nargs="*",
118
117
  )
118
+
119
+ parser.add_argument(
120
+ "--spinor",
121
+ help="whether the Wannier functions are spinor. Default: False",
122
+ action="store_true",
123
+ default=False,
124
+ )
125
+
119
126
  parser.add_argument(
120
127
  "--rcut",
121
128
  help="cutoff of spin pair distance. The default is to calculate all commensurate R point to the k mesh.",
@@ -214,6 +221,14 @@ def add_exchange_args_to_parser(parser: argparse.ArgumentParser):
214
221
  action="store_true",
215
222
  default=False,
216
223
  )
224
+
225
+ parser.add_argument(
226
+ "--ibz",
227
+ help=" use irreducible k-points in the Brillouin zone. (Note: only for computing total MAE).",
228
+ action="store_true",
229
+ default=False,
230
+ )
231
+
217
232
  return parser
218
233
 
219
234
 
@@ -7,17 +7,28 @@ from collections import defaultdict
7
7
  from shutil import rmtree
8
8
 
9
9
  import numpy as np
10
- from HamiltonIO.model.occupations import Occupations
10
+ from HamiltonIO.model.occupations import GaussOccupations
11
11
  from HamiltonIO.model.occupations import myfermi as fermi
12
12
  from pathos.multiprocessing import ProcessPool
13
13
 
14
- from TB2J.kpoints import monkhorst_pack
14
+ from TB2J.kpoints import ir_kpts, monkhorst_pack
15
15
 
16
16
  # from TB2J.mathutils.fermi import fermi
17
17
 
18
18
  MAX_EXP_ARGUMENT = np.log(sys.float_info.max)
19
19
 
20
20
 
21
+ def eigen_to_G2(H, S, efermi, energy):
22
+ """calculate green's function from eigenvalue/eigenvector for energy(e-ef): G(e-ef).
23
+ :param H: Hamiltonian matrix in eigenbasis
24
+ :param S: Overlap matrix in eigenbasis
25
+ :param efermi: fermi energy
26
+ :param energy: energy level e - efermi
27
+ """
28
+ # G = ((E+Ef) S - H)^-1
29
+ return np.linalg.inv((energy + efermi) * S - H)
30
+
31
+
21
32
  def eigen_to_G(evals, evecs, efermi, energy):
22
33
  """calculate green's function from eigenvalue/eigenvector for energy(e-ef): G(e-ef).
23
34
  :param evals: eigen values
@@ -40,7 +51,7 @@ def eigen_to_G(evals, evecs, efermi, energy):
40
51
  )
41
52
 
42
53
 
43
- def find_energy_ingap(evals, rbound, gap=4.0):
54
+ def find_energy_ingap(evals, rbound, gap=2.0):
44
55
  """
45
56
  find a energy inside a gap below rbound (right bound),
46
57
  return the energy gap top - 0.5.
@@ -59,9 +70,11 @@ class TBGreen:
59
70
  self,
60
71
  tbmodel,
61
72
  kmesh=None, # [ikpt, 3]
73
+ ibz=False, # if True, will interpolate the Green's function at Ir-kpoints
62
74
  efermi=None, # efermi
63
75
  gamma=False,
64
76
  kpts=None,
77
+ kweights=None,
65
78
  k_sym=False,
66
79
  use_cache=False,
67
80
  cache_path=None,
@@ -81,20 +94,64 @@ class TBGreen:
81
94
  self.cache_path = cache_path
82
95
  if use_cache:
83
96
  self._prepare_cache()
84
- if kpts is not None:
85
- self.kpts = kpts
86
- elif kmesh is not None:
87
- self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
88
- else:
89
- self.kpts = tbmodel.get_kpts()
90
- self.nkpts = len(self.kpts)
91
- self.kweights = np.array([1.0 / self.nkpts] * self.nkpts)
97
+ self.prepare_kpts(
98
+ kmesh=kmesh,
99
+ ibz=ibz,
100
+ gamma=gamma,
101
+ kpts=kpts,
102
+ kweights=kweights,
103
+ tbmodel=tbmodel,
104
+ )
105
+
92
106
  self.norb = tbmodel.norb
93
107
  self.nbasis = tbmodel.nbasis
94
108
  self.k_sym = k_sym
95
109
  self.nproc = nproc
96
110
  self._prepare_eigen()
97
111
 
112
+ def prepare_kpts(
113
+ self, kmesh=None, gamma=True, ibz=False, kpts=None, kweights=None, tbmodel=None
114
+ ):
115
+ """
116
+ Prepare the k-points for the calculation.
117
+
118
+ Parameters:
119
+ - kmesh (tuple): The k-mesh used to generate k-points.
120
+ - gamma (bool): Whether to include the gamma point in the k-points.
121
+ - ibz (bool): Whether to use the irreducible Brillouin zone.
122
+ - kpts (list): List of user-defined k-points.
123
+ - kweights (list): List of weights for each k-point.
124
+
125
+ Returns:
126
+ None
127
+ """
128
+ if kpts is not None:
129
+ self.kpts = kpts
130
+ self.nkpts = len(self.kpts)
131
+ self.kweights = kweights
132
+ elif kmesh is not None:
133
+ if ibz:
134
+ self.kpts, self.kweights = ir_kpts(
135
+ atoms=tbmodel.atoms,
136
+ mp_grid=kmesh,
137
+ ir=True,
138
+ is_time_reversal=False,
139
+ )
140
+ self.nkpts = len(self.kpts)
141
+ print(f"Using IBZ of kmesh of {kmesh}")
142
+ print(f"Number of kpts: {self.nkpts}")
143
+ for kpt, weight in zip(self.kpts, self.kweights):
144
+ # format the kpt and weight, use 5 digits
145
+ print(f"{kpt[0]:8.5f} {kpt[1]:8.5f} {kpt[2]:8.5f} {weight:8.5f}")
146
+ else:
147
+ self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
148
+ self.nkpts = len(self.kpts)
149
+ self.kweights = np.array([1.0 / self.nkpts] * self.nkpts)
150
+ else:
151
+ self.kpts = tbmodel.get_kpts()
152
+ self.nkpts = len(self.kpts)
153
+ self.kweights = np.array([1.0 / self.nkpts] * self.nkpts)
154
+
98
155
  def _reduce_eigens(self, evals, evecs, emin, emax):
99
156
  ts = np.logical_and(evals >= emin, evals < emax)
100
157
  ts = np.any(ts, axis=0)
@@ -106,7 +163,7 @@ class TBGreen:
106
163
  istart, iend = ts[0], ts[-1] + 1
107
164
  return evals[:, istart:iend], evecs[:, :, istart:iend]
108
165
 
109
- def find_energy_ingap(self, rbound, gap=4.0):
166
+ def find_energy_ingap(self, rbound, gap=2.0):
110
167
  return find_energy_ingap(self.evals, rbound, gap)
111
168
 
112
169
  def _prepare_cache(self):
@@ -165,7 +222,14 @@ class TBGreen:
165
222
  if self.efermi is None:
166
223
  print("Calculating Fermi energy from eigenvalues")
167
224
  print(f"Number of electrons: {self.tbmodel.nel} ")
168
- occ = Occupations(
225
+
226
+ # occ = Occupations(
227
+ # nel=self.tbmodel.nel, width=0.1, wk=self.kweights, nspin=2
228
+ # )
229
+ # self.efermi = occ.efermi(copy.deepcopy(self.evals))
230
+ # print(f"Fermi energy found: {self.efermi}")
231
+
232
+ occ = GaussOccupations(
169
233
  nel=self.tbmodel.nel, width=0.1, wk=self.kweights, nspin=2
170
234
  )
171
235
  self.efermi = occ.efermi(copy.deepcopy(self.evals))
@@ -360,7 +424,6 @@ class TBGreen:
360
424
  for iR, R in enumerate(Rpts):
361
425
  phase = np.exp(self.k2Rfactor * np.dot(R, kpt))
362
426
  GR[R] += Gkw * (phase * self.kweights[ik])
363
-
364
427
  dHRdx = dHdx.get_hamR(R)
365
428
  dGRdx[R] += Gkw @ dHRdx @ Gk
366
429
  # dGRdx[R] += Gk.dot(dHRdx).dot(Gkp)
@@ -74,6 +74,7 @@ def gen_exchange_siesta(fdf_fname, read_H_soc=False, **kwargs):
74
74
  output_path="TB2J_results",
75
75
  orb_decomposition=False,
76
76
  orth=False,
77
+ ibz=False,
77
78
  description="",
78
79
  )
79
80
  exargs.update(kwargs)
@@ -162,7 +163,7 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
162
163
  # thetas = [0, np.pi / 2, np.pi, 3 * np.pi / 2]
163
164
  # phis = [0, 0, 0, 0]
164
165
  # MAE.set_angles(thetas=thetas, phis=phis)
165
- MAE.run(output_path=f"{output_path}_anisotropy")
166
+ MAE.run(output_path=f"{output_path}_anisotropy", with_eigen=True)
166
167
  print(
167
168
  f"MAE calculation finished. The results are in {output_path} directory."
168
169
  )