TB2J 0.9.9rc2__tar.gz → 0.9.9rc4__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.9rc2 → tb2j-0.9.9rc4}/PKG-INFO +2 -2
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/MAEGreen.py +108 -40
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/exchange.py +3 -3
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/exchange_params.py +1 -1
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/siesta_interface.py +1 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/mathutils/rotate_spin.py +5 -4
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/symmetrize_J.py +22 -5
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/PKG-INFO +2 -2
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/requires.txt +1 -1
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/setup.py +2 -2
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/LICENSE +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/README.md +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/Jdownfolder.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/Jtensor.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/MAE.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/Oiju.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/Oiju_epc.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/anisotropy.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/basis.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/citation.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/contour.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/density_matrix.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/epc.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/exchangeCL2.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/exchange_pert.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/exchange_qspace.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/external/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/external/p_tqdm.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/gpaw_wrapper.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/green.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/greentest.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/abacus_api.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/abacus_wrapper.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/gen_exchange_abacus.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/orbital_api.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/stru_api.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/test_density_matrix.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/test_read_HRSR.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/abacus/test_read_stru.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/gpaw_interface.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/lawaf_interface.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/manager.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/interfaces/wannier90_interface.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_exchange.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_multibinit.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_tomsasd.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_txt.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_uppasd.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_exchange/io_vampire.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/io_merge.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/kpoints.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/mathutils/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/mathutils/fermi.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/mathutils/kR_convert.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/mathutils/lowdin.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/myTB.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/orbmap.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/pauli.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/pert.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/plot.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/rotate_atoms.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/rotate_siestaDM.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/sisl_wrapper.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/base_parser.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/constants.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/hamiltonian.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/hamiltonian_terms.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/plot.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/qsolver.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/spin_api.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/spin_xml.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/spinham/supercell.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/tensor_rotate.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/utest.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/utils.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/versioninfo.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/wannier/__init__.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/wannier/w90_parser.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J/wannier/w90_tb_parser.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/SOURCES.txt +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/dependency_links.txt +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/entry_points.txt +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/TB2J.egg-info/top_level.txt +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_downfold.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_eigen.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_magnon.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_magnon_dos.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_merge.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_rotate.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/TB2J_rotateDM.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/abacus2J.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/siesta2J.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/scripts/wann2J.py +0 -0
- {tb2j-0.9.9rc2 → tb2j-0.9.9rc4}/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.9rc4
|
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.9
|
25
25
|
Requires-Dist: pre-commit
|
26
26
|
Requires-Dist: sympair>0.1.0
|
27
27
|
|
@@ -2,9 +2,10 @@ from pathlib import Path
|
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
import tqdm
|
5
|
+
from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
|
6
|
+
from HamiltonIO.model.occupations import Occupations
|
5
7
|
from typing_extensions import DefaultDict
|
6
8
|
|
7
|
-
from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
|
8
9
|
from TB2J.exchange import ExchangeNCL
|
9
10
|
|
10
11
|
# from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
|
@@ -14,14 +15,15 @@ from TB2J.mathutils.rotate_spin import (
|
|
14
15
|
)
|
15
16
|
|
16
17
|
|
18
|
+
def get_occupation(evals, kweights, nel, width=0.1):
|
19
|
+
occ = Occupations(nel=nel, width=width, wk=kweights, nspin=2)
|
20
|
+
return occ.occupy(evals)
|
21
|
+
|
22
|
+
|
17
23
|
class MAEGreen(ExchangeNCL):
|
18
|
-
def __init__(self, angles=
|
24
|
+
def __init__(self, angles=None, **kwargs):
|
19
25
|
super().__init__(**kwargs)
|
20
26
|
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
27
|
if angles is None or angles == "axis":
|
26
28
|
self.set_angles_axis()
|
27
29
|
elif angles == "scan":
|
@@ -30,10 +32,15 @@ class MAEGreen(ExchangeNCL):
|
|
30
32
|
self.thetas = angles[0]
|
31
33
|
self.phis = angles[1]
|
32
34
|
|
35
|
+
nangles = len(self.thetas)
|
36
|
+
self.es = np.zeros(nangles, dtype=complex)
|
37
|
+
self.es_atom = np.zeros((nangles, self.natoms), dtype=complex)
|
38
|
+
self.es_atom_orb = DefaultDict(lambda: 0)
|
39
|
+
|
33
40
|
def set_angles_axis(self):
|
34
41
|
"""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]
|
42
|
+
self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2, np.pi]
|
43
|
+
self.phis = [0, 0, np.pi / 2, np.pi / 4, 0]
|
37
44
|
|
38
45
|
def set_angles_scan(self, step=15):
|
39
46
|
self.thetas = []
|
@@ -43,6 +50,32 @@ class MAEGreen(ExchangeNCL):
|
|
43
50
|
self.thetas.append(i * np.pi / 180)
|
44
51
|
self.phis.append(j * np.pi / 180)
|
45
52
|
|
53
|
+
def get_band_energy_vs_angles_from_eigen(
|
54
|
+
self,
|
55
|
+
thetas,
|
56
|
+
phis,
|
57
|
+
):
|
58
|
+
"""
|
59
|
+
Calculate the band energy for a given set of angles by using the eigenvalues and eigenvectors of the Hamiltonian.
|
60
|
+
"""
|
61
|
+
es = []
|
62
|
+
nangles = len(thetas)
|
63
|
+
self.tbmodel.set_so_strength(1.0)
|
64
|
+
for i in tqdm.trange(nangles):
|
65
|
+
theta = thetas[i]
|
66
|
+
phi = phis[i]
|
67
|
+
self.tbmodel.set_Hsoc_rotation_angle([theta, phi])
|
68
|
+
e = self.get_band_energy()
|
69
|
+
es.append(e)
|
70
|
+
return es
|
71
|
+
|
72
|
+
def get_band_energy(self):
|
73
|
+
self.width = 0.1
|
74
|
+
evals, _evecs = self.tbmodel.solve_all(self.G.kpts)
|
75
|
+
occ = get_occupation(evals, self.G.kweights, self.tbmodel.nel, width=self.width)
|
76
|
+
eband = np.sum(evals * occ * self.G.kweights[:, np.newaxis])
|
77
|
+
return eband
|
78
|
+
|
46
79
|
def get_perturbed(self, e, thetas, phis):
|
47
80
|
self.tbmodel.set_so_strength(0.0)
|
48
81
|
G0K = self.G.get_Gk_all(e)
|
@@ -59,26 +92,38 @@ class MAEGreen(ExchangeNCL):
|
|
59
92
|
GdH = G0K[ik] @ dHi
|
60
93
|
# dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
|
61
94
|
# diagonal of second order perturbation.
|
62
|
-
|
63
|
-
#dG2 = np.einsum("ij,ji->ij", GdH, GdH)
|
95
|
+
dG2diag = np.diag(GdH @ GdH)
|
96
|
+
# dG2 = np.einsum("ij,ji->ij", GdH, GdH)
|
64
97
|
dG2 = GdH * GdH.T
|
65
98
|
dG2sum = np.sum(dG2)
|
99
|
+
# print(f"dG2sum-sum: {dG2sum}")
|
100
|
+
|
101
|
+
# dG2sum = np.trace(GdH @ GdH)
|
102
|
+
# print(f"dG2sum-Tr: {dG2sum}")
|
103
|
+
# dG1sum = np.trace(GdH)
|
104
|
+
# print(f"dG1sum-Tr: {dG1sum}")
|
66
105
|
|
67
106
|
# 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]
|
107
|
+
# dE_angle[iangle] += np.trace(GdH@GdH) * self.G.kweights[ik]
|
108
|
+
# dE_angle[iangle] += np.trace(GdH@G0K[ik].T.conj()@dHi ) * self.G.kweights[ik]
|
70
109
|
dE_angle[iangle] += dG2sum * self.G.kweights[ik]
|
71
110
|
for iatom in range(self.natoms):
|
72
111
|
iorb = self.iorb(iatom)
|
73
|
-
#dG2= dG2[::2, ::2] + dG2[1::2, 1::2] + dG2[1::2, ::2] + dG2[::2, 1::2]
|
112
|
+
# dG2= dG2[::2, ::2] + dG2[1::2, 1::2] + dG2[1::2, ::2] + dG2[::2, 1::2]
|
74
113
|
dE_atom_orb = dG2[np.ix_(iorb, iorb)] * self.G.kweights[ik]
|
75
|
-
dE_atom_orb =
|
114
|
+
dE_atom_orb = (
|
115
|
+
dE_atom_orb[::2, ::2]
|
116
|
+
+ dE_atom_orb[1::2, 1::2]
|
117
|
+
+ dE_atom_orb[1::2, ::2]
|
118
|
+
+ dE_atom_orb[::2, 1::2]
|
119
|
+
)
|
76
120
|
mmat = self.mmats[iatom]
|
77
|
-
dE_atom_orb =
|
121
|
+
dE_atom_orb = mmat.T @ dE_atom_orb @ mmat
|
78
122
|
|
79
123
|
dE_angle_atom_orb[(iangle, iatom)] += dE_atom_orb
|
80
124
|
|
81
|
-
dE_atom = np.sum(
|
125
|
+
dE_atom = np.sum(dG2diag[iorb]) * self.G.kweights[ik]
|
126
|
+
# dE_atom = np.sum(dE_atom_orb)
|
82
127
|
dE_angle_atom[iangle, iatom] += dE_atom
|
83
128
|
return dE_angle, dE_angle_atom, dE_angle_atom_orb
|
84
129
|
|
@@ -93,7 +138,10 @@ class MAEGreen(ExchangeNCL):
|
|
93
138
|
# dE_angle_atoms = np.zeros((len(thetas), self.natoms), dtype=complex)
|
94
139
|
pass
|
95
140
|
|
96
|
-
def get_band_energy_vs_angles(self, thetas, phis):
|
141
|
+
def get_band_energy_vs_angles(self, thetas, phis, with_eigen=False):
|
142
|
+
if with_eigen:
|
143
|
+
self.es2 = self.get_band_energy_vs_angles_from_eigen(thetas, phis)
|
144
|
+
|
97
145
|
for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
|
98
146
|
dE_angle, dE_angle_atom, dE_angle_atom_orb = self.get_perturbed(
|
99
147
|
e, thetas, phis
|
@@ -101,17 +149,33 @@ class MAEGreen(ExchangeNCL):
|
|
101
149
|
self.es += dE_angle * self.contour.weights[ie]
|
102
150
|
self.es_atom += dE_angle_atom * self.contour.weights[ie]
|
103
151
|
for key, value in dE_angle_atom_orb.items():
|
104
|
-
self.es_atom_orb[key] +=
|
152
|
+
self.es_atom_orb[key] += (
|
153
|
+
dE_angle_atom_orb[key] * self.contour.weights[ie]
|
154
|
+
)
|
105
155
|
|
106
|
-
self.es = -np.imag(self.es) / np.pi
|
107
|
-
self.es_atom = -np.imag(self.es_atom) / np.pi
|
156
|
+
self.es = -np.imag(self.es) / (2 * np.pi)
|
157
|
+
self.es_atom = -np.imag(self.es_atom) / (2 * np.pi)
|
108
158
|
for key, value in self.es_atom_orb.items():
|
109
|
-
self.es_atom_orb[key] = -np.imag(value) / np.pi
|
159
|
+
self.es_atom_orb[key] = -np.imag(value) / (2 * np.pi)
|
110
160
|
|
111
|
-
def output(self, output_path="TB2J_anisotropy"):
|
161
|
+
def output(self, output_path="TB2J_anisotropy", with_eigen=False):
|
112
162
|
Path(output_path).mkdir(exist_ok=True)
|
113
163
|
fname = f"{output_path}/MAE.dat"
|
114
164
|
fname_orb = f"{output_path}/MAE_orb.dat"
|
165
|
+
|
166
|
+
# ouput with eigenvalues.
|
167
|
+
if with_eigen:
|
168
|
+
fname_eigen = f"{output_path}/MAE_eigen.dat"
|
169
|
+
with open(fname_eigen, "w") as f:
|
170
|
+
f.write("# theta, phi, MAE(total), MAE(atom-wise) Unit: meV\n")
|
171
|
+
for i, (theta, phi, e, es) in enumerate(
|
172
|
+
zip(self.thetas, self.phis, self.es2, self.es_atom)
|
173
|
+
):
|
174
|
+
f.write(f"{theta:.5f} {phi:.5f} {e*1e3:.8f} ")
|
175
|
+
for ea in es:
|
176
|
+
f.write(f"{ea*1e3:.8f} ")
|
177
|
+
f.write("\n")
|
178
|
+
|
115
179
|
with open(fname, "w") as f:
|
116
180
|
f.write("# theta, phi, MAE(total), MAE(atom-wise) Unit: meV\n")
|
117
181
|
for i, (theta, phi, e, es) in enumerate(
|
@@ -141,27 +205,30 @@ class MAEGreen(ExchangeNCL):
|
|
141
205
|
for iatom, ea in enumerate(eatom):
|
142
206
|
f.write(f"Atom {iatom:03d}: {ea*1e3:.8f} \n")
|
143
207
|
f.write("Orbital: ")
|
144
|
-
eorb = self.es_atom_orb[(i, iatom)]
|
208
|
+
eorb = self.es_atom_orb[(i, iatom)]
|
145
209
|
|
146
210
|
# write numpy matrix to file
|
147
211
|
f.write(
|
148
212
|
np.array2string(
|
149
|
-
eorb*1e3, precision=4, separator=",", suppress_small=True
|
213
|
+
eorb * 1e3, precision=4, separator=",", suppress_small=True
|
150
214
|
)
|
151
215
|
)
|
152
216
|
|
153
|
-
eorb_diff = eorb -
|
217
|
+
eorb_diff = eorb - self.es_atom_orb[(0, iatom)]
|
154
218
|
f.write("Diference to the first angle: ")
|
155
219
|
f.write(
|
156
220
|
np.array2string(
|
157
|
-
eorb_diff*1e3,
|
221
|
+
eorb_diff * 1e3,
|
222
|
+
precision=4,
|
223
|
+
separator=",",
|
224
|
+
suppress_small=True,
|
158
225
|
)
|
159
226
|
)
|
160
227
|
f.write("\n")
|
161
228
|
|
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)
|
229
|
+
def run(self, output_path="TB2J_anisotropy", with_eigen=False):
|
230
|
+
self.get_band_energy_vs_angles(self.thetas, self.phis, with_eigen=with_eigen)
|
231
|
+
self.output(output_path=output_path, with_eigen=with_eigen)
|
165
232
|
|
166
233
|
|
167
234
|
def abacus_get_MAE(
|
@@ -175,23 +242,24 @@ def abacus_get_MAE(
|
|
175
242
|
magnetic_elements=None,
|
176
243
|
nel=None,
|
177
244
|
width=0.1,
|
178
|
-
**kwargs
|
245
|
+
**kwargs,
|
179
246
|
):
|
180
247
|
"""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
248
|
parser = AbacusSplitSOCParser(
|
182
249
|
outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
|
183
250
|
)
|
184
251
|
model = parser.parse()
|
252
|
+
model.set_so_strength(0.0)
|
185
253
|
if nel is not None:
|
186
254
|
model.nel = nel
|
187
|
-
mae = MAEGreen(
|
255
|
+
mae = MAEGreen(
|
256
|
+
tbmodels=model,
|
257
|
+
atoms=model.atoms,
|
258
|
+
kmesh=kmesh,
|
259
|
+
efermi=None,
|
260
|
+
basis=model.basis,
|
261
|
+
angles=[thetas, phis],
|
262
|
+
magnetic_elements=magnetic_elements,
|
263
|
+
**kwargs,
|
264
|
+
)
|
188
265
|
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,8 +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 - 10.0) - self.efermi
|
54
|
-
self.emin = -
|
53
|
+
# self.emin = self.G.find_energy_ingap(rbound=self.efermi - 10.0) - self.efermi
|
54
|
+
self.emin = -22.0
|
55
55
|
print(f"A gap is found at {self.emin}, set emin to it.")
|
56
56
|
|
57
57
|
def set_tbmodels(self, tbmodels):
|
@@ -119,7 +119,7 @@ class Exchange(ExchangeParams):
|
|
119
119
|
else:
|
120
120
|
try:
|
121
121
|
atom_sym, orb_sym = base[:2]
|
122
|
-
except Exception
|
122
|
+
except Exception:
|
123
123
|
iatom = base.iatom
|
124
124
|
atom_sym = base.iatom
|
125
125
|
orb_sym = base.sym
|
@@ -171,6 +171,7 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
|
|
171
171
|
for key, val in angle.items():
|
172
172
|
# model = parser.get_model()
|
173
173
|
theta, phi = val
|
174
|
+
model.set_so_strength(1.0)
|
174
175
|
model.set_Hsoc_rotation_angle([theta, phi])
|
175
176
|
basis = dict(zip(model.orbs, list(range(model.nbasis))))
|
176
177
|
output_path_full = f"{output_path}_{key}"
|
@@ -92,15 +92,17 @@ def rotate_spinor_matrix_einsum(M, theta, phi):
|
|
92
92
|
"""
|
93
93
|
Rotate the spinor matrix M by theta and phi,
|
94
94
|
"""
|
95
|
-
|
96
|
-
|
95
|
+
shape = M.shape
|
96
|
+
n1 = np.product(shape[:-1]) // 2
|
97
|
+
n2 = M.shape[-1] // 2
|
98
|
+
Mnew = np.reshape(M, (n1, 2, n2, 2)) # .swapaxes(1, 2)
|
97
99
|
# print("Mnew:", Mnew)
|
98
100
|
U = rotation_matrix(theta, phi)
|
99
101
|
UT = U.conj().T
|
100
102
|
Mnew = np.einsum(
|
101
103
|
"ij, rjsk, kl -> risl", UT, Mnew, U, optimize=True, dtype=np.complex128
|
102
104
|
)
|
103
|
-
Mnew = Mnew.reshape(
|
105
|
+
Mnew = Mnew.reshape(shape)
|
104
106
|
return Mnew
|
105
107
|
|
106
108
|
|
@@ -111,7 +113,6 @@ def rotate_spinor_matrix_einsum_R(M, theta, phi):
|
|
111
113
|
nR = M.shape[0]
|
112
114
|
N = M.shape[1] // 2
|
113
115
|
Mnew = np.reshape(M, (nR, N, 2, N, 2)) # .swapaxes(1, 2)
|
114
|
-
# print("Mnew:", Mnew)
|
115
116
|
U = rotation_matrix(theta, phi)
|
116
117
|
UT = U.conj().T
|
117
118
|
Mnew = np.einsum(
|
@@ -1,16 +1,19 @@
|
|
1
|
-
|
2
|
-
import numpy as np
|
1
|
+
import copy
|
3
2
|
from pathlib import Path
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
from sympair import SymmetryPairFinder
|
6
|
+
|
4
7
|
from TB2J.versioninfo import print_license
|
5
|
-
import copy
|
6
8
|
|
7
9
|
|
8
10
|
class TB2JSymmetrizer:
|
9
|
-
def __init__(self, exc, symprec=1e-8, verbose=True):
|
11
|
+
def __init__(self, exc, symprec=1e-8, verbose=True, Jonly=False):
|
10
12
|
# list of pairs with the index of atoms
|
11
13
|
ijRs = exc.ijR_list_index_atom()
|
12
14
|
finder = SymmetryPairFinder(atoms=exc.atoms, pairs=ijRs, symprec=symprec)
|
13
15
|
self.verbose = verbose
|
16
|
+
self.Jonly = Jonly
|
14
17
|
|
15
18
|
if verbose:
|
16
19
|
print("=" * 30)
|
@@ -28,7 +31,7 @@ class TB2JSymmetrizer:
|
|
28
31
|
print(f"Finding crystal symmetry with symprec of {symprec} Angstrom.")
|
29
32
|
print("Symmetry found:")
|
30
33
|
print(finder.spacegroup)
|
31
|
-
print(
|
34
|
+
print("-" * 30)
|
32
35
|
self.pgdict = finder.get_symmetry_pair_group_dict()
|
33
36
|
self.exc = exc
|
34
37
|
self.new_exc = copy.deepcopy(exc)
|
@@ -51,6 +54,11 @@ class TB2JSymmetrizer:
|
|
51
54
|
for i, j, R in ijRs_spin:
|
52
55
|
symJdict[(R, i, j)] = Javg
|
53
56
|
self.new_exc.exchange_Jdict = symJdict
|
57
|
+
if self.Jonly:
|
58
|
+
self.new_exc.has_dmi = False
|
59
|
+
self.new_exc.dmi_dict = {}
|
60
|
+
self.new_exc.has_uniaxial_anistropy = False
|
61
|
+
self.new_exc.k1_dict = {}
|
54
62
|
|
55
63
|
def output(self, path="TB2J_symmetrized"):
|
56
64
|
if path is None:
|
@@ -72,6 +80,7 @@ def symmetrize_J(
|
|
72
80
|
fname="TB2J.pickle",
|
73
81
|
symprec=1e-5,
|
74
82
|
output_path="TB2J_symmetrized",
|
83
|
+
Jonly=False,
|
75
84
|
):
|
76
85
|
"""
|
77
86
|
symmetrize the exchange parameters
|
@@ -109,6 +118,14 @@ def symmetrize_J_cli():
|
|
109
118
|
default=1e-5,
|
110
119
|
help="precision for symmetry detection. default is 1e-5 Angstrom",
|
111
120
|
)
|
121
|
+
|
122
|
+
parser.add_argument(
|
123
|
+
"--Jonly",
|
124
|
+
action="store_true",
|
125
|
+
help="symmetrize only the exchange parameters and discard the DMI and anisotropic exchange",
|
126
|
+
default=False,
|
127
|
+
)
|
128
|
+
|
112
129
|
args = parser.parse_args()
|
113
130
|
if args.inpath is None:
|
114
131
|
parser.print_help()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: TB2J
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.9rc4
|
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.9
|
25
25
|
Requires-Dist: pre-commit
|
26
26
|
Requires-Dist: sympair>0.1.0
|
27
27
|
|
@@ -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_rc4"
|
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.9",
|
44
44
|
"pre-commit",
|
45
45
|
"sympair>0.1.0",
|
46
46
|
],
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|