TB2J 0.9.5rc0__py3-none-any.whl → 0.9.6rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. TB2J/MAE.py +107 -24
  2. TB2J/anisotropy.py +672 -0
  3. TB2J/contour.py +8 -0
  4. TB2J/exchange.py +43 -103
  5. TB2J/exchangeCL2.py +11 -13
  6. TB2J/exchange_params.py +213 -0
  7. TB2J/green.py +62 -27
  8. TB2J/interfaces/__init__.py +12 -0
  9. TB2J/interfaces/abacus/__init__.py +4 -0
  10. TB2J/{abacus → interfaces/abacus}/abacus_api.py +3 -3
  11. TB2J/{abacus → interfaces/abacus}/abacus_wrapper.py +11 -8
  12. TB2J/{abacus → interfaces/abacus}/gen_exchange_abacus.py +5 -3
  13. TB2J/{abacus → interfaces/abacus}/orbital_api.py +4 -4
  14. TB2J/{abacus → interfaces/abacus}/stru_api.py +11 -11
  15. TB2J/{abacus → interfaces/abacus}/test_read_HRSR.py +0 -1
  16. TB2J/{abacus → interfaces/abacus}/test_read_stru.py +5 -3
  17. TB2J/interfaces/gpaw_interface.py +54 -0
  18. TB2J/interfaces/lawaf_interface.py +129 -0
  19. TB2J/interfaces/manager.py +23 -0
  20. TB2J/interfaces/siesta_interface.py +174 -0
  21. TB2J/interfaces/wannier90_interface.py +115 -0
  22. TB2J/io_exchange/io_exchange.py +21 -7
  23. TB2J/io_merge.py +2 -1
  24. TB2J/mathutils/fermi.py +11 -6
  25. TB2J/mathutils/lowdin.py +12 -2
  26. TB2J/mathutils/rotate_spin.py +222 -4
  27. TB2J/pauli.py +11 -3
  28. TB2J/symmetrize_J.py +120 -0
  29. TB2J/utils.py +82 -1
  30. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/abacus2J.py +5 -4
  31. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/siesta2J.py +21 -4
  32. TB2J-0.9.6rc0.data/scripts/wann2J.py +96 -0
  33. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/METADATA +5 -3
  34. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/RECORD +46 -46
  35. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/WHEEL +1 -1
  36. TB2J-0.9.6rc0.dist-info/entry_points.txt +3 -0
  37. TB2J/abacus/MAE.py +0 -320
  38. TB2J/abacus/__init__.py +0 -1
  39. TB2J/abacus/occupations.py +0 -278
  40. TB2J/cut_cell.py +0 -82
  41. TB2J/io_exchange/io_pickle.py +0 -0
  42. TB2J/manager.py +0 -445
  43. TB2J/mathutils.py +0 -12
  44. TB2J/patch.py +0 -50
  45. TB2J/spinham/h_matrix.py +0 -68
  46. TB2J/spinham/obtain_J.py +0 -79
  47. TB2J/supercell.py +0 -532
  48. TB2J-0.9.5rc0.data/scripts/wann2J.py +0 -194
  49. TB2J/{abacus → interfaces/abacus}/test_density_matrix.py +1 -1
  50. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_downfold.py +0 -0
  51. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_eigen.py +0 -0
  52. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon.py +0 -0
  53. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
  54. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_merge.py +0 -0
  55. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotate.py +0 -0
  56. {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotateDM.py +0 -0
  57. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/LICENSE +0 -0
  58. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/top_level.txt +0 -0
@@ -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
@@ -0,0 +1,174 @@
1
+ import os
2
+
3
+ import numpy as np
4
+
5
+ from TB2J.exchange import ExchangeNCL
6
+ from TB2J.exchangeCL2 import ExchangeCL2
7
+
8
+ try:
9
+ from HamiltonIO.siesta import SislParser
10
+ except ImportError:
11
+ print(
12
+ "Cannot import SislWrapper from HamiltonIO.siesta. Please install HamiltonIO first."
13
+ )
14
+
15
+ np.seterr(all="raise", under="ignore")
16
+
17
+
18
+ def gen_exchange_siesta(
19
+ fdf_fname,
20
+ read_H_soc=False,
21
+ magnetic_elements=[],
22
+ include_orbs=None,
23
+ kmesh=[5, 5, 5],
24
+ emin=-12.0,
25
+ emax=0.0,
26
+ nz=100,
27
+ exclude_orbs=[],
28
+ Rcut=None,
29
+ ne=None,
30
+ nproc=1,
31
+ use_cache=False,
32
+ output_path="TB2J_results",
33
+ orb_decomposition=False,
34
+ orth=False,
35
+ description="",
36
+ ):
37
+ try:
38
+ import sisl
39
+ except ImportError:
40
+ raise ImportError("sisl cannot be imported. Please install sisl first.")
41
+
42
+ from packaging import version
43
+
44
+ if version.parse(sisl.__version__) <= version.parse("0.10.0"):
45
+ raise ImportError(
46
+ f"sisl version is {sisl.__version__}, but should be larger than 0.10.0."
47
+ )
48
+
49
+ include_orbs = {}
50
+ if isinstance(magnetic_elements, str):
51
+ magnetic_elements = [magnetic_elements]
52
+ for element in magnetic_elements:
53
+ if "_" in element:
54
+ elem = element.split("_")[0]
55
+ orb = element.split("_")[1:]
56
+ include_orbs[elem] = orb
57
+ else:
58
+ include_orbs[element] = None
59
+ magnetic_elements = list(include_orbs.keys())
60
+
61
+ # fdf = sisl.get_sile(fdf_fname)
62
+ # geom = fdf.read_geometry()
63
+ # H = fdf.read_hamiltonian()
64
+ # geom = H.geometry
65
+ parser = SislParser(
66
+ fdf_fname=fdf_fname, ispin=None, read_H_soc=read_H_soc, orth=orth
67
+ )
68
+ if parser.spin.is_colinear:
69
+ print("Reading Siesta hamiltonian: colinear spin.")
70
+ # tbmodel_up = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=0, geom=geom)
71
+ # tbmodel_dn = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=1, geom=geom)
72
+ tbmodel_up, tbmodel_dn = parser.get_model()
73
+ basis = dict(zip(tbmodel_up.orbs, list(range(tbmodel_up.norb))))
74
+ print("Starting to calculate exchange.")
75
+ description = f""" Input from collinear Siesta data.
76
+ working directory: {os.getcwd()}
77
+ fdf_fname: {fdf_fname}.
78
+ \n"""
79
+ exchange = ExchangeCL2(
80
+ tbmodels=(tbmodel_up, tbmodel_dn),
81
+ atoms=tbmodel_up.atoms,
82
+ basis=basis,
83
+ efermi=0.0,
84
+ magnetic_elements=magnetic_elements,
85
+ include_orbs=include_orbs,
86
+ kmesh=kmesh,
87
+ emin=emin,
88
+ emax=emax,
89
+ nz=nz,
90
+ exclude_orbs=exclude_orbs,
91
+ Rcut=Rcut,
92
+ ne=ne,
93
+ nproc=nproc,
94
+ use_cache=use_cache,
95
+ output_path=output_path,
96
+ description=description,
97
+ )
98
+ exchange.run(path=output_path)
99
+ print("\n")
100
+ print(f"All calculation finished. The results are in {output_path} directory.")
101
+
102
+ elif parser.spin.is_spinorbit or parser.spin.is_noncolinear:
103
+ print("Reading Siesta hamiltonian: non-colinear spin.")
104
+ model = parser.get_model()
105
+ basis = dict(zip(model.orbs, list(range(model.nbasis))))
106
+ print("Starting to calculate exchange.")
107
+ description = f""" Input from non-collinear Siesta data.
108
+ working directory: {os.getcwd()}
109
+ fdf_fname: {fdf_fname}.
110
+ Warning: The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
111
+ e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
112
+ 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.
113
+ \n"""
114
+ if not model.split_soc:
115
+ exchange = ExchangeNCL(
116
+ tbmodels=model,
117
+ atoms=model.atoms,
118
+ basis=basis,
119
+ efermi=0.0,
120
+ # FIXME:
121
+ # efermi=None,
122
+ magnetic_elements=magnetic_elements,
123
+ include_orbs=include_orbs,
124
+ kmesh=kmesh,
125
+ emin=emin,
126
+ emax=emax,
127
+ nz=nz,
128
+ exclude_orbs=exclude_orbs,
129
+ Rcut=Rcut,
130
+ ne=ne,
131
+ nproc=nproc,
132
+ use_cache=use_cache,
133
+ description=description,
134
+ output_path=output_path,
135
+ orb_decomposition=orb_decomposition,
136
+ )
137
+ exchange.run(path=output_path)
138
+ print("\n")
139
+ print(
140
+ f"All calculation finished. The results are in {output_path} directory."
141
+ )
142
+ else:
143
+ angle = {"x": (np.pi / 2, 0), "y": (np.pi / 2, np.pi / 2), "z": (0, 0)}
144
+ for key, val in angle.items():
145
+ # model = parser.get_model()
146
+ theta, phi = val
147
+ model.set_Hsoc_rotation_angle([theta, phi])
148
+ basis = dict(zip(model.orbs, list(range(model.nbasis))))
149
+ output_path_full = f"{output_path}_{key}"
150
+ exchange = ExchangeNCL(
151
+ tbmodels=model,
152
+ atoms=model.atoms,
153
+ basis=basis,
154
+ efermi=None, # set to None, compute from efermi.
155
+ magnetic_elements=magnetic_elements,
156
+ include_orbs=include_orbs,
157
+ kmesh=kmesh,
158
+ emin=emin,
159
+ emax=emax,
160
+ nz=nz,
161
+ exclude_orbs=exclude_orbs,
162
+ Rcut=Rcut,
163
+ ne=ne,
164
+ nproc=nproc,
165
+ use_cache=use_cache,
166
+ description=description,
167
+ output_path=output_path_full,
168
+ orb_decomposition=orb_decomposition,
169
+ )
170
+ exchange.run(path=output_path_full)
171
+ print("\n")
172
+ print(
173
+ f"All calculation finished. The results are in {output_path_full} directory."
174
+ )