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.
- TB2J/MAE.py +107 -24
- TB2J/anisotropy.py +672 -0
- TB2J/contour.py +8 -0
- TB2J/exchange.py +43 -103
- TB2J/exchangeCL2.py +11 -13
- TB2J/exchange_params.py +213 -0
- TB2J/green.py +62 -27
- TB2J/interfaces/__init__.py +12 -0
- TB2J/interfaces/abacus/__init__.py +4 -0
- TB2J/{abacus → interfaces/abacus}/abacus_api.py +3 -3
- TB2J/{abacus → interfaces/abacus}/abacus_wrapper.py +11 -8
- TB2J/{abacus → interfaces/abacus}/gen_exchange_abacus.py +5 -3
- TB2J/{abacus → interfaces/abacus}/orbital_api.py +4 -4
- TB2J/{abacus → interfaces/abacus}/stru_api.py +11 -11
- TB2J/{abacus → interfaces/abacus}/test_read_HRSR.py +0 -1
- TB2J/{abacus → interfaces/abacus}/test_read_stru.py +5 -3
- TB2J/interfaces/gpaw_interface.py +54 -0
- TB2J/interfaces/lawaf_interface.py +129 -0
- TB2J/interfaces/manager.py +23 -0
- TB2J/interfaces/siesta_interface.py +174 -0
- TB2J/interfaces/wannier90_interface.py +115 -0
- TB2J/io_exchange/io_exchange.py +21 -7
- TB2J/io_merge.py +2 -1
- TB2J/mathutils/fermi.py +11 -6
- TB2J/mathutils/lowdin.py +12 -2
- TB2J/mathutils/rotate_spin.py +222 -4
- TB2J/pauli.py +11 -3
- TB2J/symmetrize_J.py +120 -0
- TB2J/utils.py +82 -1
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/abacus2J.py +5 -4
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/siesta2J.py +21 -4
- TB2J-0.9.6rc0.data/scripts/wann2J.py +96 -0
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/METADATA +5 -3
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/RECORD +46 -46
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/WHEEL +1 -1
- TB2J-0.9.6rc0.dist-info/entry_points.txt +3 -0
- TB2J/abacus/MAE.py +0 -320
- TB2J/abacus/__init__.py +0 -1
- TB2J/abacus/occupations.py +0 -278
- TB2J/cut_cell.py +0 -82
- TB2J/io_exchange/io_pickle.py +0 -0
- TB2J/manager.py +0 -445
- TB2J/mathutils.py +0 -12
- TB2J/patch.py +0 -50
- TB2J/spinham/h_matrix.py +0 -68
- TB2J/spinham/obtain_J.py +0 -79
- TB2J/supercell.py +0 -532
- TB2J-0.9.5rc0.data/scripts/wann2J.py +0 -194
- TB2J/{abacus → interfaces/abacus}/test_density_matrix.py +1 -1
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_downfold.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_eigen.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_merge.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotate.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotateDM.py +0 -0
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.6rc0.dist-info}/LICENSE +0 -0
- {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
|
-
|
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
|
-
|
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.
|
15
|
-
|
16
|
-
from
|
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
|
-
|
9
|
+
|
10
|
+
# from TB2J.abacus.abacus_wrapper import AbacusParser
|
10
11
|
from HamiltonIO.abacus import AbacusParser
|
11
|
-
|
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
|
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
|
-
|
7
|
-
import numpy as np
|
6
|
+
|
8
7
|
from dataclasses import dataclass
|
9
|
-
from
|
10
|
-
|
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
|
-
|
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
|
-
|
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]
|
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(
|
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])
|
@@ -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
|
-
|
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
|
+
)
|