TB2J 0.9.7rc0__tar.gz → 0.9.9rc2__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.7rc0 → tb2j-0.9.9rc2}/PKG-INFO +2 -2
- tb2j-0.9.9rc2/TB2J/MAEGreen.py +197 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/exchange.py +17 -6
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/exchange_params.py +27 -2
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/abacus_wrapper.py +1 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/gen_exchange_abacus.py +5 -3
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/orbital_api.py +10 -8
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/siesta_interface.py +9 -21
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/orbmap.py +18 -2
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/PKG-INFO +2 -2
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/requires.txt +1 -1
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/abacus2J.py +5 -11
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/siesta2J.py +12 -10
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/setup.py +2 -2
- tb2j-0.9.7rc0/TB2J/MAEGreen.py +0 -84
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/LICENSE +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/README.md +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/Jdownfolder.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/Jtensor.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/MAE.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/Oiju.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/Oiju_epc.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/anisotropy.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/basis.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/citation.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/contour.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/density_matrix.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/epc.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/exchangeCL2.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/exchange_pert.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/exchange_qspace.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/external/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/external/p_tqdm.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/gpaw_wrapper.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/green.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/greentest.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/abacus_api.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/stru_api.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/test_density_matrix.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/test_read_HRSR.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/abacus/test_read_stru.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/gpaw_interface.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/lawaf_interface.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/manager.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/interfaces/wannier90_interface.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_exchange.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_multibinit.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_tomsasd.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_txt.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_uppasd.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_exchange/io_vampire.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/io_merge.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/kpoints.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/mathutils/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/mathutils/fermi.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/mathutils/kR_convert.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/mathutils/lowdin.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/mathutils/rotate_spin.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/myTB.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/pauli.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/pert.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/plot.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/rotate_atoms.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/rotate_siestaDM.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/sisl_wrapper.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/base_parser.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/constants.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/hamiltonian.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/hamiltonian_terms.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/plot.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/qsolver.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/spin_api.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/spin_xml.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/spinham/supercell.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/symmetrize_J.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/tensor_rotate.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/utest.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/utils.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/versioninfo.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/wannier/__init__.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/wannier/w90_parser.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J/wannier/w90_tb_parser.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/SOURCES.txt +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/dependency_links.txt +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/entry_points.txt +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/TB2J.egg-info/top_level.txt +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_downfold.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_eigen.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_magnon.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_magnon_dos.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_merge.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_rotate.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/TB2J_rotateDM.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/scripts/wann2J.py +0 -0
- {tb2j-0.9.7rc0 → tb2j-0.9.9rc2}/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.9rc2
|
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
|
@@ -21,7 +21,7 @@ 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.8
|
25
25
|
Requires-Dist: pre-commit
|
26
26
|
Requires-Dist: sympair>0.1.0
|
27
27
|
|
@@ -0,0 +1,197 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
import tqdm
|
5
|
+
from typing_extensions import DefaultDict
|
6
|
+
|
7
|
+
from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
|
8
|
+
from TB2J.exchange import ExchangeNCL
|
9
|
+
|
10
|
+
# from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
|
11
|
+
# from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
|
12
|
+
from TB2J.mathutils.rotate_spin import (
|
13
|
+
rotate_spinor_matrix,
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
class MAEGreen(ExchangeNCL):
|
18
|
+
def __init__(self, angles=[], **kwargs):
|
19
|
+
super().__init__(**kwargs)
|
20
|
+
self.natoms = len(self.atoms)
|
21
|
+
nangles = len(angles[0])
|
22
|
+
self.es = np.zeros(nangles, dtype=complex)
|
23
|
+
self.es_atom = np.zeros((nangles, self.natoms), dtype=complex)
|
24
|
+
self.es_atom_orb = DefaultDict(lambda: 0)
|
25
|
+
if angles is None or angles == "axis":
|
26
|
+
self.set_angles_axis()
|
27
|
+
elif angles == "scan":
|
28
|
+
self.set_angles_scan()
|
29
|
+
else:
|
30
|
+
self.thetas = angles[0]
|
31
|
+
self.phis = angles[1]
|
32
|
+
|
33
|
+
def set_angles_axis(self):
|
34
|
+
"""theta and phi are defined as the x, y, z, axis."""
|
35
|
+
self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2]
|
36
|
+
self.phis = [0, 0, np.pi / 2, np.pi / 4]
|
37
|
+
|
38
|
+
def set_angles_scan(self, step=15):
|
39
|
+
self.thetas = []
|
40
|
+
self.phis = []
|
41
|
+
for i in range(0, 181, step):
|
42
|
+
for j in range(0, 181, step):
|
43
|
+
self.thetas.append(i * np.pi / 180)
|
44
|
+
self.phis.append(j * np.pi / 180)
|
45
|
+
|
46
|
+
def get_perturbed(self, e, thetas, phis):
|
47
|
+
self.tbmodel.set_so_strength(0.0)
|
48
|
+
G0K = self.G.get_Gk_all(e)
|
49
|
+
Hsoc_k = self.tbmodel.get_Hk_soc(self.G.kpts)
|
50
|
+
na = len(thetas)
|
51
|
+
dE_angle = np.zeros(na, dtype=complex)
|
52
|
+
dE_angle_atom = np.zeros((na, self.natoms), dtype=complex)
|
53
|
+
# dE_angle_orbitals = np.zeros((na, self.natoms, self.norb, self.norb), dtype=complex)
|
54
|
+
# dE_angle_orbitals = DefaultDict(lambda: 0)
|
55
|
+
dE_angle_atom_orb = DefaultDict(lambda: 0)
|
56
|
+
for iangle, (theta, phi) in enumerate(zip(thetas, phis)):
|
57
|
+
for ik, dHk in enumerate(Hsoc_k):
|
58
|
+
dHi = rotate_spinor_matrix(dHk, theta, phi)
|
59
|
+
GdH = G0K[ik] @ dHi
|
60
|
+
# dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
|
61
|
+
# diagonal of second order perturbation.
|
62
|
+
# dG2diag = np.diag(GdH @ GdH)
|
63
|
+
#dG2 = np.einsum("ij,ji->ij", GdH, GdH)
|
64
|
+
dG2 = GdH * GdH.T
|
65
|
+
dG2sum = np.sum(dG2)
|
66
|
+
|
67
|
+
# dG2diag = np.diag(GdH @G0K[i].T.conj() @ dHi)
|
68
|
+
#dE_angle[iangle] += np.trace(GdH@GdH) * self.G.kweights[ik]
|
69
|
+
#dE_angle[iangle] += np.trace(GdH@G0K[ik].T.conj()@dHi ) * self.G.kweights[ik]
|
70
|
+
dE_angle[iangle] += dG2sum * self.G.kweights[ik]
|
71
|
+
for iatom in range(self.natoms):
|
72
|
+
iorb = self.iorb(iatom)
|
73
|
+
#dG2= dG2[::2, ::2] + dG2[1::2, 1::2] + dG2[1::2, ::2] + dG2[::2, 1::2]
|
74
|
+
dE_atom_orb = dG2[np.ix_(iorb, iorb)] * self.G.kweights[ik]
|
75
|
+
dE_atom_orb = dE_atom_orb[::2, ::2] + dE_atom_orb[1::2, 1::2] + dE_atom_orb[1::2, ::2] + dE_atom_orb[::2, 1::2]
|
76
|
+
mmat = self.mmats[iatom]
|
77
|
+
dE_atom_orb = mmat.T @ dE_atom_orb @ mmat
|
78
|
+
|
79
|
+
dE_angle_atom_orb[(iangle, iatom)] += dE_atom_orb
|
80
|
+
|
81
|
+
dE_atom = np.sum(dE_atom_orb)
|
82
|
+
dE_angle_atom[iangle, iatom] += dE_atom
|
83
|
+
return dE_angle, dE_angle_atom, dE_angle_atom_orb
|
84
|
+
|
85
|
+
def get_perturbed_R(self, e, thetas, phis):
|
86
|
+
self.tbmodel.set_so_strength(0.0)
|
87
|
+
# Here only the first R vector is considered.
|
88
|
+
# TODO: consider all R vectors.
|
89
|
+
# Rlist = np.zeros((1, 3), dtype=float)
|
90
|
+
# G0K = self.G.get_Gk_all(e)
|
91
|
+
# G0R = k_to_R(self.G.kpts, Rlist, G0K, self.G.kweights)
|
92
|
+
# dE_angle = np.zeros(len(thetas), dtype=complex)
|
93
|
+
# dE_angle_atoms = np.zeros((len(thetas), self.natoms), dtype=complex)
|
94
|
+
pass
|
95
|
+
|
96
|
+
def get_band_energy_vs_angles(self, thetas, phis):
|
97
|
+
for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
|
98
|
+
dE_angle, dE_angle_atom, dE_angle_atom_orb = self.get_perturbed(
|
99
|
+
e, thetas, phis
|
100
|
+
)
|
101
|
+
self.es += dE_angle * self.contour.weights[ie]
|
102
|
+
self.es_atom += dE_angle_atom * self.contour.weights[ie]
|
103
|
+
for key, value in dE_angle_atom_orb.items():
|
104
|
+
self.es_atom_orb[key] += dE_angle_atom_orb[key] * self.contour.weights[ie]
|
105
|
+
|
106
|
+
self.es = -np.imag(self.es) / np.pi
|
107
|
+
self.es_atom = -np.imag(self.es_atom) / np.pi
|
108
|
+
for key, value in self.es_atom_orb.items():
|
109
|
+
self.es_atom_orb[key] = -np.imag(value) / np.pi
|
110
|
+
|
111
|
+
def output(self, output_path="TB2J_anisotropy"):
|
112
|
+
Path(output_path).mkdir(exist_ok=True)
|
113
|
+
fname = f"{output_path}/MAE.dat"
|
114
|
+
fname_orb = f"{output_path}/MAE_orb.dat"
|
115
|
+
with open(fname, "w") as f:
|
116
|
+
f.write("# theta, phi, MAE(total), MAE(atom-wise) Unit: meV\n")
|
117
|
+
for i, (theta, phi, e, es) in enumerate(
|
118
|
+
zip(self.thetas, self.phis, self.es, self.es_atom)
|
119
|
+
):
|
120
|
+
f.write(f"{theta:.5f} {phi:.5f} {e*1e3:.8f} ")
|
121
|
+
for ea in es:
|
122
|
+
f.write(f"{ea*1e3:.8f} ")
|
123
|
+
f.write("\n")
|
124
|
+
|
125
|
+
with open(fname_orb, "w") as f:
|
126
|
+
f.write("=" * 80 + "\n")
|
127
|
+
f.write("Orbitals for each atom: \n")
|
128
|
+
f.write("=" * 80 + "\n")
|
129
|
+
f.write("Note: the energies are in meV\n")
|
130
|
+
for iatom in range(self.natoms):
|
131
|
+
f.write(f"Atom {iatom:03d}: ")
|
132
|
+
for orb in self.orbital_names[iatom]:
|
133
|
+
f.write(f"{orb} ")
|
134
|
+
f.write("\n")
|
135
|
+
for i, (theta, phi, e, eatom) in enumerate(
|
136
|
+
zip(self.thetas, self.phis, self.es, self.es_atom)
|
137
|
+
):
|
138
|
+
f.write("-" * 60 + "\n")
|
139
|
+
f.write(f"Angle {i:03d}: theta={theta:.5f} phi={phi:.5f} \n ")
|
140
|
+
f.write(f"E: {e*1e3:.8f} \n")
|
141
|
+
for iatom, ea in enumerate(eatom):
|
142
|
+
f.write(f"Atom {iatom:03d}: {ea*1e3:.8f} \n")
|
143
|
+
f.write("Orbital: ")
|
144
|
+
eorb = self.es_atom_orb[(i, iatom)]
|
145
|
+
|
146
|
+
# write numpy matrix to file
|
147
|
+
f.write(
|
148
|
+
np.array2string(
|
149
|
+
eorb*1e3, precision=4, separator=",", suppress_small=True
|
150
|
+
)
|
151
|
+
)
|
152
|
+
|
153
|
+
eorb_diff = eorb - self.es_atom_orb[(0, iatom)]
|
154
|
+
f.write("Diference to the first angle: ")
|
155
|
+
f.write(
|
156
|
+
np.array2string(
|
157
|
+
eorb_diff*1e3, precision=4, separator=",", suppress_small=True
|
158
|
+
)
|
159
|
+
)
|
160
|
+
f.write("\n")
|
161
|
+
|
162
|
+
def run(self, output_path="TB2J_anisotropy"):
|
163
|
+
self.get_band_energy_vs_angles(self.thetas, self.phis)
|
164
|
+
self.output(output_path=output_path)
|
165
|
+
|
166
|
+
|
167
|
+
def abacus_get_MAE(
|
168
|
+
path_nosoc,
|
169
|
+
path_soc,
|
170
|
+
kmesh,
|
171
|
+
thetas,
|
172
|
+
phis,
|
173
|
+
gamma=True,
|
174
|
+
output_path="TB2J_anisotropy",
|
175
|
+
magnetic_elements=None,
|
176
|
+
nel=None,
|
177
|
+
width=0.1,
|
178
|
+
**kwargs
|
179
|
+
):
|
180
|
+
"""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."""
|
181
|
+
parser = AbacusSplitSOCParser(
|
182
|
+
outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
|
183
|
+
)
|
184
|
+
model = parser.parse()
|
185
|
+
if nel is not None:
|
186
|
+
model.nel = nel
|
187
|
+
mae = MAEGreen(tbmodels=model, atoms = model.atoms, kmesh=kmesh, efermi=None, basis=model.basis, angles=[thetas, phis], magnetic_elements=magnetic_elements, **kwargs)
|
188
|
+
mae.run(output_path=output_path)
|
189
|
+
#es = mae.get_band_energy_vs_angles(thetas, phis)
|
190
|
+
#if outfile:
|
191
|
+
# with open(outfile, "w") as f:
|
192
|
+
# f.write("#theta, phi, energy\n")
|
193
|
+
# for theta, phi, e in zip(thetas, phis, es):
|
194
|
+
# f.write(f"{theta:5.3f}, {phi:5.3f}, {e:10.9f}\n")
|
195
|
+
#return es
|
196
|
+
|
197
|
+
|
@@ -50,7 +50,8 @@ class Exchange(ExchangeParams):
|
|
50
50
|
os.makedirs(self.orbpath, exist_ok=True)
|
51
51
|
|
52
52
|
def _adjust_emin(self):
|
53
|
-
self.emin = self.G.find_energy_ingap(rbound=self.efermi -
|
53
|
+
#self.emin = self.G.find_energy_ingap(rbound=self.efermi - 10.0) - self.efermi
|
54
|
+
self.emin = -12.0
|
54
55
|
print(f"A gap is found at {self.emin}, set emin to it.")
|
55
56
|
|
56
57
|
def set_tbmodels(self, tbmodels):
|
@@ -114,14 +115,19 @@ class Exchange(ExchangeParams):
|
|
114
115
|
# e.g. Fe2, dxy, _, _
|
115
116
|
if isinstance(base, str):
|
116
117
|
atom_sym, orb_sym = base.split("|")[:2]
|
118
|
+
iatom = sdict[atom_sym]
|
117
119
|
else:
|
118
|
-
|
120
|
+
try:
|
121
|
+
atom_sym, orb_sym = base[:2]
|
122
|
+
except Exception as e:
|
123
|
+
iatom = base.iatom
|
124
|
+
atom_sym = base.iatom
|
125
|
+
orb_sym = base.sym
|
119
126
|
|
120
127
|
if atom_sym in adict:
|
121
128
|
adict[atom_sym].append(orb_sym)
|
122
129
|
else:
|
123
130
|
adict[atom_sym] = [orb_sym]
|
124
|
-
iatom = sdict[atom_sym]
|
125
131
|
if iatom not in self.orb_dict:
|
126
132
|
self.orb_dict[iatom] = [i]
|
127
133
|
self.labels[iatom] = [orb_sym]
|
@@ -144,8 +150,9 @@ class Exchange(ExchangeParams):
|
|
144
150
|
)
|
145
151
|
if not self._is_collinear:
|
146
152
|
for iatom, orb in self.orb_dict.items():
|
153
|
+
print(f"iatom: {iatom}, orb: {orb}")
|
147
154
|
nsorb = len(self.orb_dict[iatom])
|
148
|
-
if nsorb % 2 != 0:
|
155
|
+
if nsorb % 2 != 0 and False:
|
149
156
|
raise ValueError(
|
150
157
|
f"""The number of spin-orbitals for atom {iatom} is not even,
|
151
158
|
{nsorb} spin-orbitals are found near this atom.
|
@@ -166,7 +173,10 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
|
|
166
173
|
self.mmats = {}
|
167
174
|
self.orbital_names = {}
|
168
175
|
self.norb_reduced = {}
|
169
|
-
|
176
|
+
print(f"self.backend_name: {self.backend_name}")
|
177
|
+
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}")
|
170
180
|
syms = self.atoms.get_chemical_symbols()
|
171
181
|
for iatom, orbs in self.labels.items():
|
172
182
|
if (self.include_orbs is not None) and syms[iatom] in self.include_orbs:
|
@@ -176,6 +186,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
|
|
176
186
|
include_only=self.include_orbs[syms[iatom]],
|
177
187
|
)
|
178
188
|
else:
|
189
|
+
print(f"orbs: {orbs}")
|
179
190
|
mmat, reduced_orbs = map_orbs_matrix(
|
180
191
|
orbs, spinor=not (self._is_collinear), include_only=None
|
181
192
|
)
|
@@ -231,7 +242,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
|
|
231
242
|
"""
|
232
243
|
sum up the contribution of all the orbitals with same (n,l,m)
|
233
244
|
"""
|
234
|
-
if self.backend_name.upper()
|
245
|
+
if self.backend_name.upper() in ["SIESTA", "ABACUS", "LCAOHAMILTONIAN"]:
|
235
246
|
mmat_i = self.mmats[iatom]
|
236
247
|
mmat_j = self.mmats[jatom]
|
237
248
|
Jorbij = mmat_i.T @ Jorbij @ mmat_j
|
@@ -56,8 +56,11 @@ class ExchangeParams:
|
|
56
56
|
):
|
57
57
|
self.efermi = efermi
|
58
58
|
self.basis = basis
|
59
|
-
self.magnetic_elements = magnetic_elements
|
60
|
-
self.include_orbs = include_orbs
|
59
|
+
# self.magnetic_elements = magnetic_elements
|
60
|
+
# self.include_orbs = include_orbs
|
61
|
+
self.magnetic_elements, self.include_orbs = self.set_magnetic_elements(
|
62
|
+
magnetic_elements, include_orbs
|
63
|
+
)
|
61
64
|
self._kmesh = kmesh
|
62
65
|
self.emin = emin
|
63
66
|
self.emax = emax
|
@@ -82,6 +85,28 @@ class ExchangeParams:
|
|
82
85
|
with open(fname, "w") as myfile:
|
83
86
|
yaml.dump(self.__dict__, myfile)
|
84
87
|
|
88
|
+
def set_magnetic_elements(self, magnetic_elements, include_orbs):
|
89
|
+
# magnetic_elements = exargs.pop("magnetic_elements")
|
90
|
+
# include_orbs = exargs.pop("include_orbs")
|
91
|
+
if include_orbs is None:
|
92
|
+
include_orbs = {}
|
93
|
+
if isinstance(magnetic_elements, str):
|
94
|
+
magnetic_elements = [magnetic_elements]
|
95
|
+
print(f"magnetic_elements: {magnetic_elements}")
|
96
|
+
print(f"include_orbs: {include_orbs}")
|
97
|
+
for element in magnetic_elements:
|
98
|
+
if "_" in element:
|
99
|
+
elem = element.split("_")[0]
|
100
|
+
orb = element.split("_")[1:]
|
101
|
+
include_orbs[elem] = orb
|
102
|
+
else:
|
103
|
+
include_orbs[element] = None
|
104
|
+
|
105
|
+
print(f"magnetic_elements: {magnetic_elements}")
|
106
|
+
print(f"include_orbs: {include_orbs}")
|
107
|
+
magnetic_elements = list(include_orbs.keys())
|
108
|
+
return magnetic_elements, include_orbs
|
109
|
+
|
85
110
|
|
86
111
|
def add_exchange_args_to_parser(parser: argparse.ArgumentParser):
|
87
112
|
parser.add_argument(
|
@@ -27,7 +27,7 @@ def gen_exchange_abacus(
|
|
27
27
|
exclude_orbs=[],
|
28
28
|
Rcut=None,
|
29
29
|
use_cache=False,
|
30
|
-
|
30
|
+
nproc=1,
|
31
31
|
output_path="TB2J_results",
|
32
32
|
orb_decomposition=False,
|
33
33
|
description=None,
|
@@ -60,9 +60,10 @@ data directory: {outpath}
|
|
60
60
|
nz=nz,
|
61
61
|
exclude_orbs=exclude_orbs,
|
62
62
|
Rcut=Rcut,
|
63
|
-
|
63
|
+
nproc=nproc,
|
64
64
|
use_cache=use_cache,
|
65
65
|
output_path=output_path,
|
66
|
+
orb_decomposition=orb_decomposition,
|
66
67
|
description=description,
|
67
68
|
)
|
68
69
|
exchange.run(path=output_path)
|
@@ -86,8 +87,9 @@ data directory: {outpath}
|
|
86
87
|
nz=nz,
|
87
88
|
exclude_orbs=exclude_orbs,
|
88
89
|
Rcut=Rcut,
|
89
|
-
|
90
|
+
nproc=nproc,
|
90
91
|
use_cache=use_cache,
|
92
|
+
orb_decomposition=orb_decomposition,
|
91
93
|
description=description,
|
92
94
|
)
|
93
95
|
exchange.run()
|
@@ -16,13 +16,14 @@ class AbacusOrbital:
|
|
16
16
|
Orbital class
|
17
17
|
"""
|
18
18
|
|
19
|
-
iatom: int
|
20
|
-
sym: str
|
21
|
-
spin: int
|
22
|
-
element: str
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
iatom: int = 0
|
20
|
+
sym: str = ""
|
21
|
+
spin: int = 0
|
22
|
+
element: str = ""
|
23
|
+
n: int = 0
|
24
|
+
l: int = 0
|
25
|
+
m: int = 0
|
26
|
+
z: int = 0
|
26
27
|
|
27
28
|
|
28
29
|
def parse_abacus_orbital(fname):
|
@@ -38,10 +39,11 @@ def parse_abacus_orbital(fname):
|
|
38
39
|
iatom, element, l, m, z, sym = seg
|
39
40
|
iatom = int(iatom)
|
40
41
|
ispin = 0
|
42
|
+
n = 0
|
41
43
|
l = int(l)
|
42
44
|
m = int(m)
|
43
45
|
z = int(z)
|
44
|
-
orbs.append(AbacusOrbital(iatom, sym, ispin, element, l, m, z))
|
46
|
+
orbs.append(AbacusOrbital(iatom, sym, ispin, element, n, l, m, z))
|
45
47
|
line = myfile.readline()
|
46
48
|
return orbs
|
47
49
|
|
@@ -89,18 +89,6 @@ def gen_exchange_siesta(fdf_fname, read_H_soc=False, **kwargs):
|
|
89
89
|
f"sisl version is {sisl.__version__}, but should be larger than 0.10.0."
|
90
90
|
)
|
91
91
|
|
92
|
-
magnetic_elements = exargs.pop("magnetic_elements")
|
93
|
-
include_orbs = exargs.pop("include_orbs")
|
94
|
-
if isinstance(magnetic_elements, str):
|
95
|
-
magnetic_elements = [magnetic_elements]
|
96
|
-
for element in magnetic_elements:
|
97
|
-
if "_" in element:
|
98
|
-
elem = element.split("_")[0]
|
99
|
-
orb = element.split("_")[1:]
|
100
|
-
include_orbs[elem] = orb
|
101
|
-
else:
|
102
|
-
include_orbs[element] = None
|
103
|
-
magnetic_elements = list(include_orbs.keys())
|
104
92
|
output_path = exargs.pop("output_path")
|
105
93
|
|
106
94
|
parser = SislParser(
|
@@ -122,8 +110,8 @@ def gen_exchange_siesta(fdf_fname, read_H_soc=False, **kwargs):
|
|
122
110
|
atoms=tbmodel_up.atoms,
|
123
111
|
basis=basis,
|
124
112
|
efermi=0.0,
|
125
|
-
magnetic_elements=magnetic_elements,
|
126
|
-
include_orbs=
|
113
|
+
# magnetic_elements=exargs['magnetic_elements'],
|
114
|
+
# include_orbs=ex
|
127
115
|
**exargs,
|
128
116
|
)
|
129
117
|
exchange.run(path=output_path)
|
@@ -149,8 +137,8 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
|
|
149
137
|
atoms=model.atoms,
|
150
138
|
basis=basis,
|
151
139
|
efermi=0.0,
|
152
|
-
magnetic_elements=magnetic_elements,
|
153
|
-
include_orbs=include_orbs,
|
140
|
+
# magnetic_elements=magnetic_elements,
|
141
|
+
# include_orbs=include_orbs,
|
154
142
|
output_path=output_path,
|
155
143
|
**exargs,
|
156
144
|
)
|
@@ -167,14 +155,14 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
|
|
167
155
|
atoms=model.atoms,
|
168
156
|
basis=basis,
|
169
157
|
efermi=None,
|
170
|
-
magnetic_elements=magnetic_elements,
|
171
|
-
include_orbs=include_orbs,
|
158
|
+
# magnetic_elements=magnetic_elements,
|
159
|
+
# include_orbs=include_orbs,
|
172
160
|
**exargs,
|
173
161
|
)
|
174
162
|
# thetas = [0, np.pi / 2, np.pi, 3 * np.pi / 2]
|
175
163
|
# phis = [0, 0, 0, 0]
|
176
164
|
# MAE.set_angles(thetas=thetas, phis=phis)
|
177
|
-
MAE.run(output_path=output_path)
|
165
|
+
MAE.run(output_path=f"{output_path}_anisotropy")
|
178
166
|
print(
|
179
167
|
f"MAE calculation finished. The results are in {output_path} directory."
|
180
168
|
)
|
@@ -191,8 +179,8 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
|
|
191
179
|
atoms=model.atoms,
|
192
180
|
basis=basis,
|
193
181
|
efermi=None, # set to None, compute from efermi.
|
194
|
-
magnetic_elements=magnetic_elements,
|
195
|
-
include_orbs=include_orbs,
|
182
|
+
# magnetic_elements=magnetic_elements,
|
183
|
+
# include_orbs=include_orbs,
|
196
184
|
**exargs,
|
197
185
|
)
|
198
186
|
exchange.run(path=output_path_full)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import re
|
2
2
|
from collections import defaultdict
|
3
|
+
|
3
4
|
import numpy as np
|
4
5
|
|
5
6
|
|
@@ -7,30 +8,45 @@ def split_orb_name(name):
|
|
7
8
|
"""
|
8
9
|
split name to : n, l, label
|
9
10
|
"""
|
10
|
-
m = re.findall(r"(
|
11
|
+
m = re.findall(r"([a-z\d\-\^\*]*)(.*)", name)
|
11
12
|
m = m[0]
|
12
13
|
return m[0], m[1]
|
13
14
|
|
14
15
|
|
15
16
|
def map_orbs_matrix(orblist, spinor=False, include_only=None):
|
17
|
+
"""
|
18
|
+
map the orbitals to a matrix
|
19
|
+
Method:
|
20
|
+
1. split the orbital name to n, l, label
|
21
|
+
2. group the orbitals by n, l
|
22
|
+
3. create a matrix with 1 for each orbital in the group
|
23
|
+
4. return the matrix and the group names
|
24
|
+
"""
|
25
|
+
|
16
26
|
if spinor:
|
17
27
|
orblist = orblist[::2]
|
18
28
|
|
19
29
|
norb = len(orblist)
|
20
30
|
|
31
|
+
print("orblist: ", orblist)
|
21
32
|
ss = [split_orb_name(orb) for orb in orblist]
|
22
33
|
orbdict = dict(zip(ss, range(norb)))
|
23
34
|
|
24
35
|
reduced_orbdict = defaultdict(lambda: [])
|
25
36
|
|
37
|
+
print(f"Orbital dictionary: {orbdict}")
|
38
|
+
print("include_only: ", include_only)
|
39
|
+
|
26
40
|
if include_only is None:
|
27
41
|
for key, val in orbdict.items():
|
28
42
|
reduced_orbdict[key[0]].append(val)
|
29
43
|
else:
|
30
44
|
for key, val in orbdict.items():
|
31
|
-
if key[0][:2] in include_only:
|
45
|
+
if key[0][:2] in include_only or key[0][:1] in include_only:
|
46
|
+
# [:2] for 3d, 4d, 5d, etc. and [:1] for s, p, d, etc
|
32
47
|
reduced_orbdict[key[0]].append(val)
|
33
48
|
|
49
|
+
print(f"reduced_orbdict: {reduced_orbdict}")
|
34
50
|
reduced_orbs = tuple(reduced_orbdict.keys())
|
35
51
|
ngroup = len(reduced_orbdict)
|
36
52
|
mmat = np.zeros((norb, ngroup), dtype=int)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: TB2J
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.9rc2
|
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
|
@@ -21,7 +21,7 @@ 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.8
|
25
25
|
Requires-Dist: pre-commit
|
26
26
|
Requires-Dist: sympair>0.1.0
|
27
27
|
|
@@ -81,6 +81,7 @@ def run_abacus2J():
|
|
81
81
|
)
|
82
82
|
|
83
83
|
parser.add_argument(
|
84
|
+
"--nproc",
|
84
85
|
"--np",
|
85
86
|
help="number of cpu cores to use in parallel, default: 1",
|
86
87
|
default=1,
|
@@ -121,28 +122,21 @@ def run_abacus2J():
|
|
121
122
|
print("Please input the magnetic elements, e.g. --elements Fe Ni")
|
122
123
|
sys.exit()
|
123
124
|
|
124
|
-
include_orbs = {}
|
125
|
-
for element in args.elements:
|
126
|
-
if "_" in element:
|
127
|
-
elem = element.split("_")[0]
|
128
|
-
orb = element.split("_")[1:]
|
129
|
-
include_orbs[elem] = orb
|
130
|
-
else:
|
131
|
-
include_orbs[element] = None
|
125
|
+
# include_orbs = {}
|
132
126
|
|
133
127
|
gen_exchange_abacus(
|
134
128
|
path=args.path,
|
135
129
|
suffix=args.suffix,
|
136
130
|
kmesh=args.kmesh,
|
137
|
-
magnetic_elements=
|
138
|
-
include_orbs=
|
131
|
+
magnetic_elements=args.elements,
|
132
|
+
include_orbs={},
|
139
133
|
Rcut=args.rcut,
|
140
134
|
emin=args.emin,
|
141
135
|
nz=args.nz,
|
142
136
|
description=args.description,
|
143
137
|
output_path=args.output_path,
|
144
138
|
use_cache=args.use_cache,
|
145
|
-
nproc=args.
|
139
|
+
nproc=args.nproc,
|
146
140
|
exclude_orbs=args.exclude_orbs,
|
147
141
|
orb_decomposition=args.orb_decomposition,
|
148
142
|
)
|
@@ -128,20 +128,22 @@ def run_siesta2J():
|
|
128
128
|
print("Please input the magnetic elements, e.g. --elements Fe Ni")
|
129
129
|
sys.exit()
|
130
130
|
|
131
|
-
include_orbs = {}
|
132
|
-
for element in args.elements:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
131
|
+
# include_orbs = {}
|
132
|
+
# for element in args.elements:
|
133
|
+
# if "_" in element:
|
134
|
+
# elem = element.split("_")[0]
|
135
|
+
# orb = element.split("_")[1:]
|
136
|
+
# include_orbs[elem] = orb
|
137
|
+
# else:
|
138
|
+
# include_orbs[element] = None
|
139
139
|
|
140
140
|
gen_exchange_siesta(
|
141
141
|
fdf_fname=args.fdf_fname,
|
142
142
|
kmesh=args.kmesh,
|
143
|
-
magnetic_elements=list(include_orbs.keys()),
|
144
|
-
include_orbs=include_orbs,
|
143
|
+
# magnetic_elements=list(include_orbs.keys()),
|
144
|
+
# include_orbs=include_orbs,
|
145
|
+
magnetic_elements=args.elements,
|
146
|
+
include_orbs={},
|
145
147
|
Rcut=args.rcut,
|
146
148
|
emin=args.emin,
|
147
149
|
emax=args.emax,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
from setuptools import find_packages, setup
|
3
3
|
|
4
|
-
__version__ = "0.9.
|
4
|
+
__version__ = "0.9.9_rc2"
|
5
5
|
|
6
6
|
long_description = """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. """
|
7
7
|
|
@@ -40,7 +40,7 @@ setup(
|
|
40
40
|
"tqdm",
|
41
41
|
"pathos",
|
42
42
|
"packaging>=20.0",
|
43
|
-
"HamiltonIO>=0.1.
|
43
|
+
"HamiltonIO>=0.1.8",
|
44
44
|
"pre-commit",
|
45
45
|
"sympair>0.1.0",
|
46
46
|
],
|
tb2j-0.9.7rc0/TB2J/MAEGreen.py
DELETED
@@ -1,84 +0,0 @@
|
|
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()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|