TB2J 0.9.5rc0__tar.gz → 0.9.7rc0__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.
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/PKG-INFO +5 -3
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/MAE.py +144 -27
- tb2j-0.9.7rc0/TB2J/MAEGreen.py +84 -0
- tb2j-0.9.7rc0/TB2J/anisotropy.py +672 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/contour.py +8 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/exchange.py +38 -172
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/exchangeCL2.py +11 -13
- tb2j-0.9.7rc0/TB2J/exchange_params.py +213 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/green.py +62 -27
- tb2j-0.9.7rc0/TB2J/interfaces/__init__.py +12 -0
- tb2j-0.9.7rc0/TB2J/interfaces/abacus/__init__.py +4 -0
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/abacus_api.py +3 -3
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/abacus_wrapper.py +11 -8
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/gen_exchange_abacus.py +5 -3
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/orbital_api.py +4 -4
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/stru_api.py +11 -11
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/test_read_HRSR.py +0 -1
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/test_read_stru.py +5 -3
- tb2j-0.9.7rc0/TB2J/interfaces/gpaw_interface.py +54 -0
- tb2j-0.9.7rc0/TB2J/interfaces/lawaf_interface.py +129 -0
- tb2j-0.9.7rc0/TB2J/interfaces/manager.py +23 -0
- tb2j-0.9.7rc0/TB2J/interfaces/siesta_interface.py +202 -0
- tb2j-0.9.7rc0/TB2J/interfaces/wannier90_interface.py +115 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_exchange.py +21 -7
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_merge.py +2 -1
- tb2j-0.9.7rc0/TB2J/mathutils/fermi.py +27 -0
- tb2j-0.9.7rc0/TB2J/mathutils/lowdin.py +22 -0
- tb2j-0.9.7rc0/TB2J/mathutils/rotate_spin.py +274 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/pauli.py +11 -3
- tb2j-0.9.7rc0/TB2J/symmetrize_J.py +120 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/utils.py +82 -1
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J.egg-info/PKG-INFO +5 -3
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J.egg-info/SOURCES.txt +20 -10
- tb2j-0.9.7rc0/TB2J.egg-info/entry_points.txt +3 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J.egg-info/requires.txt +4 -2
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/abacus2J.py +5 -4
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/siesta2J.py +21 -4
- tb2j-0.9.7rc0/scripts/wann2J.py +96 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/setup.py +12 -5
- tb2j-0.9.5rc0/TB2J/abacus/__init__.py +0 -1
- tb2j-0.9.5rc0/TB2J/manager.py +0 -445
- tb2j-0.9.5rc0/TB2J/mathutils/fermi.py +0 -22
- tb2j-0.9.5rc0/TB2J/mathutils/lowdin.py +0 -12
- tb2j-0.9.5rc0/TB2J/mathutils/rotate_spin.py +0 -56
- tb2j-0.9.5rc0/scripts/wann2J.py +0 -194
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/LICENSE +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/README.md +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/Jdownfolder.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/Jtensor.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/Oiju.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/Oiju_epc.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/basis.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/citation.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/density_matrix.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/epc.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/exchange_pert.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/exchange_qspace.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/external/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/external/p_tqdm.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/gpaw_wrapper.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/greentest.py +0 -0
- {tb2j-0.9.5rc0/TB2J → tb2j-0.9.7rc0/TB2J/interfaces}/abacus/test_density_matrix.py +1 -1
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_multibinit.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_tomsasd.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_txt.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_uppasd.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/io_exchange/io_vampire.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/kpoints.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/mathutils/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/mathutils/kR_convert.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/myTB.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/orbmap.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/pert.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/plot.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/rotate_atoms.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/rotate_siestaDM.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/sisl_wrapper.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/base_parser.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/constants.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/hamiltonian.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/hamiltonian_terms.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/plot.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/qsolver.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/spin_api.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/spin_xml.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/spinham/supercell.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/tensor_rotate.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/utest.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/versioninfo.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/wannier/__init__.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/wannier/w90_parser.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J/wannier/w90_tb_parser.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J.egg-info/dependency_links.txt +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/TB2J.egg-info/top_level.txt +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_downfold.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_eigen.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_magnon.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_magnon_dos.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_merge.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_rotate.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/scripts/TB2J_rotateDM.py +0 -0
- {tb2j-0.9.5rc0 → tb2j-0.9.7rc0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: TB2J
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.7rc0
|
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
|
@@ -14,13 +14,15 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
14
14
|
Classifier: License :: OSI Approved :: BSD License
|
15
15
|
Requires-Python: >=3.6
|
16
16
|
License-File: LICENSE
|
17
|
-
Requires-Dist: numpy
|
17
|
+
Requires-Dist: numpy<2.0
|
18
18
|
Requires-Dist: scipy
|
19
19
|
Requires-Dist: matplotlib
|
20
20
|
Requires-Dist: ase>=3.19
|
21
21
|
Requires-Dist: tqdm
|
22
22
|
Requires-Dist: pathos
|
23
23
|
Requires-Dist: packaging>=20.0
|
24
|
-
Requires-Dist: HamiltonIO>=0.1.
|
24
|
+
Requires-Dist: HamiltonIO>=0.1.7
|
25
|
+
Requires-Dist: pre-commit
|
26
|
+
Requires-Dist: sympair>0.1.0
|
25
27
|
|
26
28
|
TB2J is a Python package aimed to compute automatically the magnetic interactions (superexchange and Dzyaloshinskii-Moriya) between atoms of magnetic crystals from DFT Hamiltonian based on Wannier functions or Linear combination of atomic orbitals. It uses the Green's function method and take the local rigid spin rotation as a perturbation. The package can take the output from Wannier90, which is interfaced with many density functional theory codes or from codes based on localised orbitals. A minimal user input is needed, which allows for an easily integration into a high-throughput workflows.
|
@@ -1,20 +1,26 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
|
3
|
+
import matplotlib.pyplot as plt
|
1
4
|
import numpy as np
|
2
|
-
|
3
|
-
|
5
|
+
import tqdm
|
6
|
+
|
7
|
+
# from TB2J.abacus.abacus_wrapper import AbacusSplitSOCParser
|
8
|
+
from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
|
9
|
+
from HamiltonIO.model.occupations import Occupations
|
10
|
+
from HamiltonIO.siesta import SislParser
|
11
|
+
from scipy.linalg import eigh
|
12
|
+
|
13
|
+
from TB2J.contour import Contour
|
14
|
+
from TB2J.green import TBGreen
|
15
|
+
|
16
|
+
# from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
|
4
17
|
from TB2J.kpoints import monkhorst_pack
|
5
|
-
from TB2J.mathutils.fermi import fermi
|
6
18
|
from TB2J.mathutils.kR_convert import R_to_k
|
7
|
-
|
8
|
-
from
|
9
|
-
from
|
10
|
-
|
11
|
-
|
12
|
-
from TB2J.mathutils.rotate_spin import spherical_to_cartesian
|
13
|
-
from HamiltonIO.model.occupations import Occupations
|
14
|
-
#from TB2J.abacus.abacus_wrapper import AbacusSplitSOCParser
|
15
|
-
from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
|
16
|
-
from HamiltonIO.siesta import SislParser, SiestaHamiltonian
|
17
|
-
import tqdm
|
19
|
+
|
20
|
+
# from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
|
21
|
+
from TB2J.mathutils.rotate_spin import (
|
22
|
+
rotate_spinor_matrix,
|
23
|
+
)
|
18
24
|
|
19
25
|
|
20
26
|
def get_occupation(evals, kweights, nel, width=0.1):
|
@@ -29,12 +35,25 @@ def get_density_matrix(evals=None, evecs=None, kweights=None, nel=None, width=0.
|
|
29
35
|
|
30
36
|
|
31
37
|
class MAE:
|
32
|
-
def __init__(
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
model,
|
41
|
+
kmesh=None,
|
42
|
+
gamma=True,
|
43
|
+
kpts=None,
|
44
|
+
kweights=None,
|
45
|
+
width=0.1,
|
46
|
+
nel=None,
|
47
|
+
):
|
33
48
|
self.model = model
|
34
49
|
if nel is not None:
|
35
50
|
self.model.nel = nel
|
36
|
-
|
37
|
-
|
51
|
+
if kpts is None:
|
52
|
+
self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
|
53
|
+
self.kweights = np.ones(len(self.kpts), dtype=float) / len(self.kpts)
|
54
|
+
else:
|
55
|
+
self.kpts = kpts
|
56
|
+
self.kweights = kweights
|
38
57
|
self.width = width
|
39
58
|
|
40
59
|
def get_band_energy(self):
|
@@ -87,39 +106,137 @@ class MAE:
|
|
87
106
|
return es
|
88
107
|
|
89
108
|
|
109
|
+
class MAEGreen(MAE):
|
110
|
+
def __init__(
|
111
|
+
self,
|
112
|
+
model,
|
113
|
+
kmesh=None,
|
114
|
+
gamma=True,
|
115
|
+
kpts=None,
|
116
|
+
kweights=None,
|
117
|
+
nel=None,
|
118
|
+
width=0.1,
|
119
|
+
**kwargs,
|
120
|
+
):
|
121
|
+
self.model = model
|
122
|
+
if nel is not None:
|
123
|
+
self.model.nel = nel
|
124
|
+
if kpts is None:
|
125
|
+
self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
|
126
|
+
self.kweights = np.ones(len(self.kpts), dtype=float) / len(self.kpts)
|
127
|
+
else:
|
128
|
+
self.kpts = kpts
|
129
|
+
self.kweights = kweights
|
130
|
+
self.width = width
|
131
|
+
model.set_so_strength(0.0)
|
132
|
+
evals, evecs = model.solve_all(self.kpts)
|
133
|
+
occ = Occupations(
|
134
|
+
nel=self.model.nel, width=self.width, wk=self.kweights, nspin=2
|
135
|
+
)
|
136
|
+
# occ.occupy(evals)
|
137
|
+
efermi = occ.efermi(evals)
|
138
|
+
print(f"{efermi=}")
|
139
|
+
self.G = TBGreen(model, kmesh, efermi=efermi, gamma=gamma, **kwargs)
|
140
|
+
self.emin = -12
|
141
|
+
self.emax = 0
|
142
|
+
self.nz = 50
|
143
|
+
self._prepare_elist()
|
144
|
+
|
145
|
+
def _prepare_elist(self, method="legendre"):
|
146
|
+
"""
|
147
|
+
prepare list of energy for integration.
|
148
|
+
The path has three segments:
|
149
|
+
emin --1-> emin + 1j*height --2-> emax+1j*height --3-> emax
|
150
|
+
"""
|
151
|
+
self.contour = Contour(self.emin, self.emax)
|
152
|
+
# if method.lower() == "rectangle":
|
153
|
+
# self.contour.build_path_rectangle(
|
154
|
+
# height=self.height, nz1=self.nz1, nz2=self.nz2, nz3=self.nz3
|
155
|
+
# )
|
156
|
+
if method.lower() == "semicircle":
|
157
|
+
self.contour.build_path_semicircle(npoints=self.nz, endpoint=True)
|
158
|
+
elif method.lower() == "legendre":
|
159
|
+
self.contour.build_path_legendre(npoints=self.nz, endpoint=True)
|
160
|
+
else:
|
161
|
+
raise ValueError(f"The path cannot be of type {method}.")
|
162
|
+
|
163
|
+
def get_efermi(self):
|
164
|
+
evals, evecs = self.model.solve_all(self.kpts)
|
165
|
+
occ = Occupations(
|
166
|
+
nel=self.model.nel, width=self.model.width, wk=self.kweights, nspin=2
|
167
|
+
)
|
168
|
+
occ.get_efermi(evals, self.kweights)
|
169
|
+
|
170
|
+
def get_perturbed(self, e, thetas, phis):
|
171
|
+
G0K = self.G.get_Gk_all(e)
|
172
|
+
Hsoc_k = self.model.get_Hk_soc(self.kpts)
|
173
|
+
dE_ang = []
|
174
|
+
for theta, phi in zip(thetas, phis):
|
175
|
+
dE = 0.0
|
176
|
+
for i, dHk in enumerate(Hsoc_k):
|
177
|
+
dHi = rotate_spinor_matrix(dHk, theta, phi)
|
178
|
+
GdH = G0K[i] @ dHi
|
179
|
+
# dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
|
180
|
+
dE += np.trace(GdH @ GdH) * self.kweights[i]
|
181
|
+
dE_ang.append(dE)
|
182
|
+
return np.array(dE_ang)
|
183
|
+
|
184
|
+
def get_band_energy_vs_angles(self, thetas, phis):
|
185
|
+
es = np.zeros(len(thetas))
|
186
|
+
for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
|
187
|
+
dE_angle = self.get_perturbed(e, thetas, phis)
|
188
|
+
es += np.imag(dE_angle * self.contour.weights[ie])
|
189
|
+
return -es / np.pi
|
190
|
+
|
191
|
+
|
90
192
|
def get_model_energy(model, kmesh, gamma=True):
|
91
193
|
ham = MAE(model, kmesh, gamma=gamma)
|
92
194
|
return ham.get_band_energy()
|
93
195
|
|
94
196
|
|
95
197
|
def abacus_get_MAE(
|
96
|
-
path_nosoc,
|
198
|
+
path_nosoc,
|
199
|
+
path_soc,
|
200
|
+
kmesh,
|
201
|
+
thetas,
|
202
|
+
phis,
|
203
|
+
gamma=True,
|
204
|
+
outfile="MAE.txt",
|
205
|
+
nel=None,
|
206
|
+
width=0.1,
|
97
207
|
):
|
98
208
|
"""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."""
|
99
209
|
parser = AbacusSplitSOCParser(
|
100
210
|
outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
|
101
211
|
)
|
102
212
|
model = parser.parse()
|
103
|
-
|
104
|
-
|
213
|
+
if nel is not None:
|
214
|
+
model.nel = nel
|
215
|
+
ham = MAEGreen(model, kmesh, gamma=gamma, width=width)
|
216
|
+
es = ham.get_band_energy_vs_angles(thetas, phis)
|
105
217
|
if outfile:
|
106
218
|
with open(outfile, "w") as f:
|
107
|
-
f.write("#theta,
|
108
|
-
for theta,
|
109
|
-
f.write(f"{theta:5.3f}, {
|
219
|
+
f.write("#theta, phi, energy\n")
|
220
|
+
for theta, phi, e in zip(thetas, phis, es):
|
221
|
+
f.write(f"{theta:5.3f}, {phi:5.3f}, {e:10.9f}\n")
|
110
222
|
return es
|
111
223
|
|
112
224
|
|
113
|
-
def siesta_get_MAE(
|
225
|
+
def siesta_get_MAE(
|
226
|
+
fdf_fname, kmesh, thetas, phis, gamma=True, outfile="MAE.txt", nel=None, width=0.1
|
227
|
+
):
|
114
228
|
""" """
|
115
|
-
model= SislParser(fdf_fname=fdf_fname, read_H_soc=True).get_model()
|
116
|
-
|
229
|
+
model = SislParser(fdf_fname=fdf_fname, read_H_soc=True).get_model()
|
230
|
+
if nel is not None:
|
231
|
+
model.nel = nel
|
232
|
+
ham = MAEGreen(model, kmesh, gamma=gamma, width=width)
|
233
|
+
# es = ham.get_band_energy_vs_angles(thetas, phis)
|
117
234
|
es = ham.get_band_energy_vs_angles(thetas, phis)
|
118
235
|
if outfile:
|
119
236
|
with open(outfile, "w") as f:
|
120
237
|
f.write("#theta, psi, energy\n")
|
121
238
|
for theta, psi, e in zip(thetas, phis, es):
|
122
|
-
#f.write(f"{theta}, {psi}, {e}\n")
|
239
|
+
# f.write(f"{theta}, {psi}, {e}\n")
|
123
240
|
f.write(f"{theta:5.3f}, {psi:5.3f}, {e:10.9f}\n")
|
124
241
|
return es
|
125
242
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
import tqdm
|
5
|
+
|
6
|
+
# from TB2J.abacus.abacus_wrapper import AbacusSplitSOCParser
|
7
|
+
from TB2J.exchange import ExchangeNCL
|
8
|
+
|
9
|
+
# from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
|
10
|
+
# from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
|
11
|
+
from TB2J.mathutils.rotate_spin import (
|
12
|
+
rotate_spinor_matrix,
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
class MAEGreen(ExchangeNCL):
|
17
|
+
def __init__(self, angles=None, **kwargs):
|
18
|
+
super().__init__(**kwargs)
|
19
|
+
self.es = None
|
20
|
+
self.natoms = len(self.atoms)
|
21
|
+
if angles is None or angles == "axis":
|
22
|
+
self.set_angles_axis()
|
23
|
+
elif angles == "scan":
|
24
|
+
self.set_angles_scan()
|
25
|
+
|
26
|
+
def set_angles_axis(self):
|
27
|
+
"""theta and phi are defined as the x, y, z, axis."""
|
28
|
+
self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2]
|
29
|
+
self.phis = [0, 0, np.pi / 2, np.pi / 4]
|
30
|
+
|
31
|
+
def set_angles_scan(self, step=15):
|
32
|
+
self.thetas = []
|
33
|
+
self.phis = []
|
34
|
+
for i in range(0, 181, step):
|
35
|
+
for j in range(0, 181, step):
|
36
|
+
self.thetas.append(i * np.pi / 180)
|
37
|
+
self.phis.append(j * np.pi / 180)
|
38
|
+
|
39
|
+
def get_perturbed(self, e, thetas, phis):
|
40
|
+
self.tbmodel.set_so_strength(0.0)
|
41
|
+
G0K = self.G.get_Gk_all(e)
|
42
|
+
Hsoc_k = self.tbmodel.get_Hk_soc(self.G.kpts)
|
43
|
+
na = len(thetas)
|
44
|
+
dE_angle = np.zeros(na, dtype=complex)
|
45
|
+
dE_angle_atoms = np.zeros((na, self.natoms), dtype=complex)
|
46
|
+
for iangle, (theta, phi) in enumerate(zip(thetas, phis)):
|
47
|
+
for ik, dHk in enumerate(Hsoc_k):
|
48
|
+
dHi = rotate_spinor_matrix(dHk, theta, phi)
|
49
|
+
GdH = G0K[ik] @ dHi
|
50
|
+
# dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
|
51
|
+
# diagonal of second order perturbation.
|
52
|
+
dG2diag = np.diag(GdH @ GdH)
|
53
|
+
# dG2diag = np.diag(GdH @G0K[i].T.conj() @ dHi)
|
54
|
+
dE_angle[iangle] += np.sum(dG2diag) * self.G.kweights[ik]
|
55
|
+
for iatom in range(self.natoms):
|
56
|
+
dE_atom = np.sum(dG2diag[self.iorb(iatom)]) * self.G.kweights[ik]
|
57
|
+
dE_angle_atoms[iangle, iatom] += dE_atom
|
58
|
+
return dE_angle, dE_angle_atoms
|
59
|
+
|
60
|
+
def get_band_energy_vs_angles(self, thetas, phis):
|
61
|
+
nangles = len(thetas)
|
62
|
+
self.es = np.zeros(nangles, dtype=float)
|
63
|
+
self.es_atoms = np.zeros((nangles, self.natoms), dtype=float)
|
64
|
+
for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
|
65
|
+
dE_angle, dE_angle_atoms = self.get_perturbed(e, thetas, phis)
|
66
|
+
self.es -= np.imag(dE_angle * self.contour.weights[ie]) / np.pi
|
67
|
+
self.es_atoms -= np.imag(dE_angle_atoms * self.contour.weights[ie]) / np.pi
|
68
|
+
|
69
|
+
def output(self, output_path="TB2J_anisotropy"):
|
70
|
+
Path(output_path).mkdir(exist_ok=True)
|
71
|
+
fname = f"{output_path}/MAE.dat"
|
72
|
+
with open(fname, "w") as f:
|
73
|
+
f.write("# theta phi MAE, MAEatom1, atom2, ...\n")
|
74
|
+
for i, (theta, phi, e, es) in enumerate(
|
75
|
+
zip(self.thetas, self.phis, self.es, self.es_atoms)
|
76
|
+
):
|
77
|
+
f.write(f"{theta:.5f} {phi:.5f} {e:.8f} ")
|
78
|
+
for ea in es:
|
79
|
+
f.write(f"{ea:.8f} ")
|
80
|
+
f.write("\n")
|
81
|
+
|
82
|
+
def run(self, output_path="TB2J_anisotropy"):
|
83
|
+
self.get_band_energy_vs_angles(self.thetas, self.phis)
|
84
|
+
self.output()
|