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/green.py CHANGED
@@ -1,14 +1,19 @@
1
- import numpy as np
2
- from collections import defaultdict
3
- from ase.dft.kpoints import monkhorst_pack
4
- from shutil import rmtree
1
+ import copy
5
2
  import os
3
+ import pickle
4
+ import sys
6
5
  import tempfile
6
+ from collections import defaultdict
7
+ from shutil import rmtree
8
+
9
+ import numpy as np
10
+ from HamiltonIO.model.occupations import Occupations
11
+ from HamiltonIO.model.occupations import myfermi as fermi
7
12
  from pathos.multiprocessing import ProcessPool
8
- import sys
9
- import pickle
10
- import warnings
11
- from TB2J.mathutils.fermi import fermi
13
+
14
+ from TB2J.kpoints import monkhorst_pack
15
+
16
+ # from TB2J.mathutils.fermi import fermi
12
17
 
13
18
  MAX_EXP_ARGUMENT = np.log(sys.float_info.max)
14
19
 
@@ -22,9 +27,16 @@ def eigen_to_G(evals, evecs, efermi, energy):
22
27
  :returns: Green's function G,
23
28
  :rtype: Matrix with same shape of the Hamiltonian (and eigenvector)
24
29
  """
25
- return (
26
- np.einsum("ij, j-> ij", evecs, 1.0 / (-evals + (energy + efermi)))
27
- @ evecs.conj().T
30
+ # return (
31
+ # np.einsum("ij, j-> ij", evecs, 1.0 / (-evals + (energy + efermi)))
32
+ # @ evecs.conj().T
33
+ # )
34
+ return np.einsum(
35
+ "ib, b, jb-> ij",
36
+ evecs,
37
+ 1.0 / (-evals + (energy + efermi)),
38
+ evecs.conj(),
39
+ optimize=True,
28
40
  )
29
41
 
30
42
 
@@ -46,8 +58,10 @@ class TBGreen:
46
58
  def __init__(
47
59
  self,
48
60
  tbmodel,
49
- kmesh, # [ikpt, 3]
50
- efermi, # efermi
61
+ kmesh=None, # [ikpt, 3]
62
+ efermi=None, # efermi
63
+ gamma=False,
64
+ kpts=None,
51
65
  k_sym=False,
52
66
  use_cache=False,
53
67
  cache_path=None,
@@ -67,12 +81,14 @@ class TBGreen:
67
81
  self.cache_path = cache_path
68
82
  if use_cache:
69
83
  self._prepare_cache()
70
- if kmesh is not None:
71
- self.kpts = monkhorst_pack(size=kmesh)
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)
72
88
  else:
73
89
  self.kpts = tbmodel.get_kpts()
74
90
  self.nkpts = len(self.kpts)
75
- self.kweights = [1.0 / self.nkpts] * self.nkpts
91
+ self.kweights = np.array([1.0 / self.nkpts] * self.nkpts)
76
92
  self.norb = tbmodel.norb
77
93
  self.nbasis = tbmodel.nbasis
78
94
  self.k_sym = k_sym
@@ -145,9 +161,19 @@ class TBGreen:
145
161
  if not saveH:
146
162
  self.H = None
147
163
 
148
- self.evals, self.evecs = self._reduce_eigens(
149
- self.evals, self.evecs, emin=self.efermi - 10.0, emax=self.efermi + 10.1
150
- )
164
+ # get efermi
165
+ if self.efermi is None:
166
+ print("Calculating Fermi energy from eigenvalues")
167
+ print(f"Number of electrons: {self.tbmodel.nel} ")
168
+ occ = Occupations(
169
+ nel=self.tbmodel.nel, width=0.1, wk=self.kweights, nspin=2
170
+ )
171
+ self.efermi = occ.efermi(copy.deepcopy(self.evals))
172
+ print(f"Fermi energy found: {self.efermi}")
173
+
174
+ # self.evals, self.evecs = self._reduce_eigens(
175
+ # self.evals, self.evecs, emin=self.efermi - 15.0, emax=self.efermi + 10.1
176
+ # )
151
177
  if self._use_cache:
152
178
  evecs = self.evecs
153
179
  self.evecs_shape = self.evecs.shape
@@ -216,20 +242,22 @@ class TBGreen:
216
242
  rho = np.zeros((self.nbasis, self.nbasis), dtype=complex)
217
243
  if self.is_orthogonal:
218
244
  for ik, _ in enumerate(self.kpts):
245
+ evecs_k = self.get_evecs(ik)
246
+ # chekc if any of the evecs element is nan
219
247
  rho += (
220
- (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
221
- @ self.get_evecs(ik).T.conj()
248
+ (evecs_k * fermi(self.evals[ik], self.efermi, nspin=2))
249
+ @ evecs_k.T.conj()
222
250
  * self.kweights[ik]
223
251
  )
224
252
  else:
225
253
  for ik, _ in enumerate(self.kpts):
226
254
  rho += (
227
- (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
255
+ (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi, nspin=2))
228
256
  @ self.get_evecs(ik).T.conj()
229
257
  @ self.get_Sk(ik)
230
258
  * self.kweights[ik]
231
259
  )
232
-
260
+ # check if rho has nan values
233
261
  return rho
234
262
 
235
263
  def get_rho_R(self, Rlist):
@@ -238,7 +266,10 @@ class TBGreen:
238
266
  for ik, kpt in enumerate(self.kpts):
239
267
  evec = self.get_evecs(ik)
240
268
  rhok = np.einsum(
241
- "ib,b, bj-> ij", evec, fermi(self.evals[ik], self.efermi), evec.conj().T
269
+ "ib,b, bj-> ij",
270
+ evec,
271
+ fermi(self.evals[ik], self.efermi, nspin=2),
272
+ evec.conj().T,
242
273
  )
243
274
  for iR, R in enumerate(Rlist):
244
275
  rho_R[iR] += rhok * np.exp(self.k2Rfactor * kpt @ R) * self.kweights[ik]
@@ -252,16 +283,20 @@ class TBGreen:
252
283
  def get_density(self):
253
284
  return np.real(np.diag(self.get_density_matrix()))
254
285
 
255
- def get_Gk(self, ik, energy):
286
+ def get_Gk(self, ik, energy, evals=None, evecs=None):
256
287
  """Green's function G(k) for one energy
257
288
  G(\epsilon)= (\epsilon I- H)^{-1}
258
289
  :param ik: indices for kpoint
259
290
  :returns: Gk
260
291
  :rtype: a matrix of indices (nbasis, nbasis)
261
292
  """
293
+ if evals is None:
294
+ evals = self.get_evalue(ik)
295
+ if evecs is None:
296
+ evecs = self.get_evecs(ik)
262
297
  Gk = eigen_to_G(
263
- evals=self.get_evalue(ik),
264
- evecs=self.get_evecs(ik),
298
+ evals=evals,
299
+ evecs=evecs,
265
300
  efermi=self.efermi,
266
301
  energy=energy,
267
302
  )
@@ -0,0 +1,12 @@
1
+ from .abacus import gen_exchange_abacus
2
+ from .manager import Manager
3
+ from .siesta_interface import gen_exchange_siesta
4
+ from .wannier90_interface import WannierManager, gen_exchange
5
+
6
+ __all__ = [
7
+ "Manager",
8
+ "gen_exchange_siesta",
9
+ "WannierManager",
10
+ "gen_exchange",
11
+ "gen_exchange_abacus",
12
+ ]
@@ -0,0 +1,4 @@
1
+ from .abacus_wrapper import AbacusParser, AbacusWrapper
2
+ from .gen_exchange_abacus import gen_exchange_abacus
3
+
4
+ __all__ = ["AbacusWrapper", "AbacusParser", "gen_exchange_abacus"]
@@ -1,10 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
- import numpy as np
3
- from scipy import sparse
4
- from scipy.sparse import csr_matrix
5
2
  import re
6
3
  import struct
7
4
 
5
+ import numpy as np
6
+ from scipy.sparse import csr_matrix
7
+
8
8
 
9
9
  class XR_matrix:
10
10
  def __init__(self, nspin, XR_fileName):
@@ -3,17 +3,20 @@
3
3
  """
4
4
  The abacus wrapper
5
5
  """
6
- from pathlib import Path
6
+
7
7
  import os
8
+ from pathlib import Path
9
+
8
10
  import numpy as np
9
11
  from scipy.linalg import eigh
10
- from copy import deepcopy
12
+
11
13
  from TB2J.mathutils.rotate_spin import rotate_Matrix_from_z_to_spherical
12
- from TB2J.utils import symbol_number_list
13
14
  from TB2J.myTB import AbstractTB
14
- from TB2J.abacus.abacus_api import read_HR_SR
15
- from TB2J.abacus.orbital_api import parse_abacus_orbital
16
- from TB2J.abacus.stru_api import read_abacus, read_abacus_out
15
+ from TB2J.utils import symbol_number_list
16
+
17
+ from .abacus_api import read_HR_SR
18
+ from .orbital_api import parse_abacus_orbital
19
+ from .stru_api import read_abacus
17
20
 
18
21
 
19
22
  class AbacusWrapper(AbstractTB):
@@ -36,7 +39,6 @@ class AbacusWrapper(AbstractTB):
36
39
  self.set_HR_soc(HR_soc=HR_soc, HR_nosoc=HR_nosoc, HR_full=HR)
37
40
  self.soc_rotation_angle = 0.0
38
41
 
39
-
40
42
  def set_HR_soc(self, HR_soc=None, HR_nosoc=None, HR_full=None):
41
43
  self.split_soc = True
42
44
  self.HR_soc = HR_soc
@@ -329,16 +331,17 @@ def test_abacus_wrapper_collinear():
329
331
  # print(H.diagonal().real)
330
332
  # print(model_up.get_HR0().diagonal().real)
331
333
  print(parser.efermi)
334
+ print(atoms)
332
335
 
333
336
 
334
337
  def test_abacus_wrapper_ncl():
335
338
  outpath = "/Users/hexu/projects/TB2J_abacus/abacus-tb2j-master/abacus_example/case_Fe/2_soc/OUT.Fe"
336
-
337
339
  parser = AbacusParser(outpath=outpath, spin=None, binary=False)
338
340
  atoms = parser.read_atoms()
339
341
  model = parser.get_models()
340
342
  H, S, E, V = model.HSE_k([0, 0, 0])
341
343
  print(parser.efermi)
344
+ print(atoms)
342
345
 
343
346
 
344
347
  if __name__ == "__main__":
@@ -6,9 +6,11 @@ The main function to compute exchange interaction from abacus data
6
6
 
7
7
  import os
8
8
  from pathlib import Path
9
- #from TB2J.abacus.abacus_wrapper import AbacusParser
9
+
10
+ # from TB2J.abacus.abacus_wrapper import AbacusParser
10
11
  from HamiltonIO.abacus import AbacusParser
11
- from TB2J.exchange import ExchangeNCL, ExchangeCL
12
+
13
+ from TB2J.exchange import ExchangeNCL
12
14
  from TB2J.exchangeCL2 import ExchangeCL2
13
15
 
14
16
 
@@ -65,7 +67,7 @@ data directory: {outpath}
65
67
  )
66
68
  exchange.run(path=output_path)
67
69
  print("\n")
68
- print(f"All calculation finsihed. The results are in {output_path} directory.")
70
+ print(f"All calculation finished. The results are in {output_path} directory.")
69
71
  else:
70
72
  tbmodel = parser.get_models()
71
73
  print("Starting to calculate exchange.")
@@ -3,11 +3,11 @@
3
3
  """
4
4
  Parser for the abacus orbital file
5
5
  """
6
- from pathlib import Path
7
- import numpy as np
6
+
8
7
  from dataclasses import dataclass
9
- from collections import namedtuple
10
- from TB2J.utils import symbol_number, symbol_number_list
8
+ from pathlib import Path
9
+
10
+ from TB2J.utils import symbol_number_list
11
11
 
12
12
 
13
13
  @dataclass
@@ -8,17 +8,17 @@ Modified on Wed Aug 01 11:44:51 2022
8
8
  @author: Ji Yu-yang
9
9
  """
10
10
 
11
- import re
12
- import warnings
13
- import numpy as np
14
11
  import os
12
+ import re
15
13
  import shutil
14
+ import warnings
16
15
  from pathlib import Path
17
16
 
17
+ import numpy as np
18
18
  from ase import Atoms
19
- from ase.units import Bohr, Hartree, GPa, mol, _me, Rydberg
20
- from ase.utils import lazymethod, lazyproperty, reader, writer
21
19
  from ase.calculators.singlepoint import SinglePointDFTCalculator, arrays_to_kpoints
20
+ from ase.units import Bohr, GPa, Hartree, Rydberg, _me, mol
21
+ from ase.utils import lazymethod, lazyproperty, reader, writer
22
22
 
23
23
  _re_float = r"[-+]?\d+\.*\d*(?:[Ee][-+]\d+)?"
24
24
  AU_to_MASS = mol * _me * 1e3
@@ -697,7 +697,7 @@ def read_abacus(fd, latname=None, verbose=False):
697
697
  )
698
698
  symbols = specie_lines[:, 0]
699
699
  ntype = len(symbols)
700
- mass = specie_lines[:, 1].astype(float)
700
+ # mass = specie_lines[:, 1].astype(float)
701
701
  try:
702
702
  atom_potential = dict(zip(symbols, specie_lines[:, 2].tolist()))
703
703
  except IndexError:
@@ -789,7 +789,7 @@ def read_abacus(fd, latname=None, verbose=False):
789
789
 
790
790
  # symbols, magnetism
791
791
  sym = [symbol] * number
792
- masses = [mass] * number
792
+ # masses = [mass] * number
793
793
  atom_mags = [float(sub_block.group(1))] * number
794
794
  for j in range(number):
795
795
  atom_symbol.append(sym[j])
@@ -1121,7 +1121,7 @@ class AbacusOutHeaderChunk(AbacusOutChunk):
1121
1121
  def str_to_kpoints(val_in):
1122
1122
  lines = (
1123
1123
  re.search(
1124
- rf"KPOINTS\s*DIRECT_X\s*DIRECT_Y\s*DIRECT_Z\s*WEIGHT([\s\S]+?)DONE",
1124
+ r"KPOINTS\s*DIRECT_X\s*DIRECT_Y\s*DIRECT_Z\s*WEIGHT([\s\S]+?)DONE",
1125
1125
  val_in,
1126
1126
  )
1127
1127
  .group(1)
@@ -1349,7 +1349,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
1349
1349
  def _parse_ionic_block(self):
1350
1350
  """Parse the ionic block from the output file"""
1351
1351
  step_pattern = re.compile(
1352
- rf"(?:[NON]*SELF-|STEP OF|RELAX CELL)([\s\S]+?)charge density convergence is achieved"
1352
+ r"(?:[NON]*SELF-|STEP OF|RELAX CELL)([\s\S]+?)charge density convergence is achieved"
1353
1353
  )
1354
1354
 
1355
1355
  return step_pattern.findall(self.contents)
@@ -1384,7 +1384,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
1384
1384
  == "Lattice relaxation is converged!"
1385
1385
  )
1386
1386
  res = np.zeros((self.ion_steps), dtype=bool)
1387
- if lat_arr[-1] == True:
1387
+ if lat_arr[-1]:
1388
1388
  res[-1] = 1
1389
1389
 
1390
1390
  return res.astype(bool)
@@ -1805,7 +1805,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
1805
1805
  @lazyproperty
1806
1806
  def n_iter(self):
1807
1807
  """The number of SCF iterations needed to converge the SCF cycle for the chunk"""
1808
- step_pattern = re.compile(rf"ELEC\s*=\s*[+]?(\d+)")
1808
+ step_pattern = re.compile(r"ELEC\s*=\s*[+]?(\d+)")
1809
1809
 
1810
1810
  try:
1811
1811
  return int(step_pattern.findall(self._ionic_block)[-1])
@@ -1,5 +1,4 @@
1
1
  from abacus_api import read_HR_SR
2
- import numpy as np
3
2
 
4
3
 
5
4
  def main():
@@ -3,15 +3,17 @@
3
3
  """
4
4
  @File : test_read_stru.py
5
5
  @Time : 2024/02/02 09:52:23
6
- @Author : Shen Zhen-Xiong
6
+ @Author : Shen Zhen-Xiong
7
7
  @Email : shenzx@iai.ustc.edu.cn
8
8
  """
9
+
9
10
  import os
10
- from stru_api import read_abacus, write_abacus, read_input
11
+
12
+ from stru_api import read_abacus, read_input, write_abacus
11
13
 
12
14
 
13
15
  def main():
14
- stru_fe = read_abacus(os.path.join(os.getcwd(), "input/Fe.STRU"))
16
+ # stru_fe = read_abacus(os.path.join(os.getcwd(), "input/Fe.STRU"))
15
17
  stru_sr2mn2o6 = read_abacus(
16
18
  os.path.join(os.getcwd(), "input/Sr2Mn2O6.STRU"), verbose=True
17
19
  )
@@ -0,0 +1,54 @@
1
+ import os
2
+
3
+ import numpy as np
4
+
5
+ from TB2J.exchange import ExchangeNCL
6
+ from TB2J.gpaw_wrapper import GPAWWrapper
7
+ from TB2J.utils import auto_assign_basis_name
8
+
9
+
10
+ def gen_exchange_gpaw(
11
+ gpw_fname,
12
+ magnetic_elements=[],
13
+ kmesh=[3, 3, 3],
14
+ emin=-12.0,
15
+ emax=0.0,
16
+ nz=50,
17
+ exclude_orbs=[],
18
+ Rcut=None,
19
+ use_cache=False,
20
+ output_path="TB2J_results",
21
+ description="",
22
+ ):
23
+ print("Reading from GPAW data and calculate electronic structure.")
24
+ model = GPAWWrapper(gpw_fname=gpw_fname)
25
+ efermi = model.calc.get_fermi_level()
26
+ print(f"Fermi Energy: {efermi}")
27
+ poses = np.vstack([model.positions, model.positions])
28
+ basis, _ = auto_assign_basis_name(
29
+ poses,
30
+ model.atoms,
31
+ write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
32
+ )
33
+
34
+ if model.calc.get_spin_polarized():
35
+ print("Starting to calculate exchange.")
36
+ exchange = ExchangeNCL(
37
+ tbmodels=model,
38
+ atoms=model.atoms,
39
+ efermi=efermi,
40
+ basis=basis,
41
+ magnetic_elements=magnetic_elements,
42
+ kmesh=kmesh,
43
+ emin=emin,
44
+ emax=emax,
45
+ nz=nz,
46
+ exclude_orbs=exclude_orbs,
47
+ Rcut=Rcut,
48
+ use_cache=use_cache,
49
+ output_path=output_path,
50
+ description=description,
51
+ )
52
+ exchange.run(path=output_path)
53
+ print("\n")
54
+ print(f"All calculation finished. The results are in {output_path} directory.")
@@ -0,0 +1,129 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+
5
+ from HamiltonIO.lawaf import LawafHamiltonian as Ham
6
+
7
+ from TB2J.exchange_params import add_exchange_args_to_parser, parser_argument_to_dict
8
+ from TB2J.versioninfo import print_license
9
+
10
+ from .manager import Manager
11
+
12
+
13
+ class LaWaFManager(Manager):
14
+ def __init__(
15
+ self,
16
+ path,
17
+ prefix_up,
18
+ prefix_dn,
19
+ prefix_SOC,
20
+ colinear=True,
21
+ wannier_type="LaWaF",
22
+ **kwargs,
23
+ ):
24
+ # models and basis
25
+ if colinear:
26
+ tbmodels, basis, atoms = self.prepare_model_colinear(
27
+ path, prefix_up, prefix_dn
28
+ )
29
+ else:
30
+ tbmodels, basis, atoms = self.prepare_model_ncl(path, prefix_SOC)
31
+
32
+ description = self.description(path, prefix_up, prefix_dn, prefix_SOC, colinear)
33
+ kwargs["description"] = description
34
+
35
+ super().__init__(atoms, tbmodels, basis, colinear=colinear, **kwargs)
36
+
37
+ def prepare_model_colinear(self, path, prefix_up, prefix_dn):
38
+ print("Reading LawaF hamiltonian: spin up.")
39
+ tbmodel_up = Ham.load_pickle(os.path.join(path, f"{prefix_up}.pickle"))
40
+ print("Reading LaWaF hamiltonian: spin down.")
41
+ tbmodel_dn = Ham.load_pickle(os.path.join(path, f"{prefix_dn}.pickle"))
42
+ tbmodels = (tbmodel_up, tbmodel_dn)
43
+ basis = tbmodel_up.wann_names
44
+ atoms = tbmodel_up.atoms
45
+ return tbmodels, basis, atoms
46
+
47
+ def prepare_model_ncl(self, path, prefix_SOC):
48
+ print("Reading LaWaF hamiltonian: non-colinear spin.")
49
+ tbmodel = Ham.load_pickle(os.path.join(path, f"{prefix_SOC}.pickle"))
50
+ basis = tbmodel.wann_names
51
+ atoms = tbmodel.atoms
52
+ return tbmodel, basis, atoms
53
+
54
+ def description(self, path, prefix_up, prefix_dn, prefix_SOC, colinear=True):
55
+ if colinear:
56
+ description = f""" Input from collinear LaWaF data.
57
+ Tight binding data from {path}.
58
+ Prefix of wannier function files:{prefix_up} and {prefix_dn}.
59
+ Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
60
+ \n"""
61
+
62
+ else:
63
+ description = f""" Input from non-collinear LaWaF data.
64
+ Tight binding data from {path}.
65
+ Prefix of wannier function files:{prefix_SOC}.
66
+ Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
67
+ The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
68
+ e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
69
+ 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.\n"""
70
+
71
+ return description
72
+
73
+
74
+ def lawaf2J_cli():
75
+ print_license()
76
+ parser = argparse.ArgumentParser(
77
+ description="lawaf2J: Using magnetic force theorem to calculate exchange parameter J from wannier functions in LaWaF"
78
+ )
79
+ parser.add_argument(
80
+ "--path", help="path to the wannier files", default="./", type=str
81
+ )
82
+
83
+ parser.add_argument(
84
+ "--spinor",
85
+ help="if the calculation is spinor, default is False",
86
+ default=False,
87
+ action="store_true",
88
+ )
89
+
90
+ parser.add_argument(
91
+ "--prefix_spinor",
92
+ help="prefix to the spinor wannier files",
93
+ default="lawaf_spinor.pickle",
94
+ type=str,
95
+ )
96
+ parser.add_argument(
97
+ "--prefix_up",
98
+ help="prefix to the spin up wannier files",
99
+ default="lawaf_up",
100
+ type=str,
101
+ )
102
+ parser.add_argument(
103
+ "--prefix_down",
104
+ help="prefix to the spin down wannier files",
105
+ default="lawaf_dn",
106
+ type=str,
107
+ )
108
+ add_exchange_args_to_parser(parser)
109
+
110
+ args = parser.parse_args()
111
+
112
+ if args.efermi is None:
113
+ print("Please input fermi energy using --efermi ")
114
+ sys.exit()
115
+ if args.elements is None:
116
+ print("Please input the magnetic elements, e.g. --elements Fe Ni")
117
+ sys.exit()
118
+
119
+ kwargs = parser_argument_to_dict(args)
120
+
121
+ manager = LaWaFManager(
122
+ path=args.path,
123
+ prefix_up=args.prefix_up,
124
+ prefix_dn=args.prefix_down,
125
+ prefix_SOC=args.prefix_spinor,
126
+ colinear=not args.spinor,
127
+ **kwargs,
128
+ )
129
+ return manager
@@ -0,0 +1,23 @@
1
+ from TB2J.exchange import ExchangeNCL
2
+ from TB2J.exchange_qspace import ExchangeCLQspace
3
+ from TB2J.exchangeCL2 import ExchangeCL2
4
+
5
+
6
+ class Manager:
7
+ def __init__(self, atoms, models, basis, colinear, **kwargs):
8
+ # computing exchange
9
+ print("Starting to calculate exchange.")
10
+ ExchangeClass = self.select_exchange(colinear)
11
+ exchange = ExchangeClass(tbmodels=models, atoms=atoms, basis=basis, **kwargs)
12
+ output_path = kwargs.get("output_path", "TB2J_results")
13
+ exchange.run(path=output_path)
14
+ print(f"All calculation finished. The results are in {output_path} directory.")
15
+
16
+ def select_exchange(self, colinear, qspace=False):
17
+ if colinear:
18
+ if qspace:
19
+ return ExchangeCLQspace
20
+ else:
21
+ return ExchangeCL2
22
+ else:
23
+ return ExchangeNCL