TB2J 0.9.0.2__py3-none-any.whl → 0.9.0.3__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/io_merge.py CHANGED
@@ -48,7 +48,8 @@ class SpinIO_merge(SpinIO):
48
48
 
49
49
  def _set_projection_vectors(self):
50
50
 
51
- spinat = self.spinat
51
+ norm = np.linalg.norm(self.spinat, axis=-1).reshape(-1, 1)
52
+ spinat = self.spinat / norm
52
53
  idx = [self.ind_atoms[i] for i in self.index_spin if i >= 0]
53
54
  projv = {}
54
55
  for i, j in combinations_with_replacement(range(self.nspin), 2):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.9.0.2
3
+ Version: 0.9.0.3
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
@@ -1,13 +1,11 @@
1
1
  TB2J/Jdownfolder.py,sha256=Rmg6KfQ-Lkhei5daTJ2POzr0XL-R1WM-rzUnDcfoDhc,9595
2
2
  TB2J/Jtensor.py,sha256=t6OsqrSlYW6Im4H7ykVAW8Al_pFXN4C5yj2UEsV6r7g,3181
3
- TB2J/MAE.py,sha256=-KWqxjKJvPFuxsMjm0c3nESyUFDeFTqsV7QzPJN-Fxo,7579
4
3
  TB2J/Oiju.py,sha256=cNGv8N5uH_swGq7cnAt2OyiDfqtjLlLrwseGu0E4iaM,3383
5
4
  TB2J/Oiju_epc.py,sha256=oytM3NYW7nWmklrGgNlqwIpI_JYv_hb7ZnR4o9nYNog,6809
6
5
  TB2J/__init__.py,sha256=hcEWkag_UvLm1ZSbjsgcTWkGVlR3Bwmzg1QYAwsvf-g,24
7
6
  TB2J/basis.py,sha256=DFo6_QUwjBwisP6zGxvoO0lpGTMDPAOkiL9giNCjOjA,1558
8
7
  TB2J/citation.py,sha256=gcQeyJZaT1Qrtsl8Y3s4neOH3-vvgmIcCvXeV2o3vj0,2891
9
8
  TB2J/contour.py,sha256=aw8LX6wVFCRPhcpkzuI0jGnHisvk4cezvUhkF_6Yx94,2633
10
- TB2J/cut_cell.py,sha256=kr9WeQhBQLm8QXL2B3NcsSYmSw-OAtJk3f9wksAOZbs,2952
11
9
  TB2J/density_matrix.py,sha256=D5k8Oe21OCiLVORNYbo4TZOFG0slrQSbj91kJ3TMFjs,1514
12
10
  TB2J/epc.py,sha256=zLbtqZJhDr8DnnGN6YENcXwrMb3Qxu6KB08mLy9Pw20,3474
13
11
  TB2J/exchange.py,sha256=dsXQhlxXaBurxa7z3YkBjqmEFFtfEy1xaHf0VT3eKZE,29581
@@ -17,20 +15,18 @@ TB2J/exchange_qspace.py,sha256=ZL68qBGFUaQ9BsSPsJaaoWOr9RssPiqX34R_9I3nk_8,8436
17
15
  TB2J/gpaw_wrapper.py,sha256=aJ--9Dtyq7jOP1Hkh-Sh1nWcfXm6zKcljOCO0DNCAr0,6890
18
16
  TB2J/green.py,sha256=QAJbDaR91QLres5gUPk37iqVsuQdPTt92VtEYLCl240,13170
19
17
  TB2J/greentest.py,sha256=2ISSfhor9ecSEOi_E6b4Cv26wEIQlwlzca0ru8z44_E,1603
20
- TB2J/io_merge.py,sha256=t85k3L6IL9X5ys-PWK7CzResb3xJsyqM3LAlKPUe9vM,6825
18
+ TB2J/io_merge.py,sha256=E1_GfAB2HGpW-ipaO2lqU9SvaslwkiLxssn4DqJpMT8,6899
21
19
  TB2J/kpoints.py,sha256=6XK2KqTncidEq3o9GuO6VEZRPNTRtWeXg9QfcV-9smI,532
22
20
  TB2J/manager.py,sha256=4-4x9jJRHpUEqJuhc5HqpXfh2-Ze5G9Wg8gOtn-AqR4,15372
23
21
  TB2J/mathutils.py,sha256=tHA6q3KPDpXLIbZHdDZ2NU5s886VVM_oEG490zQ6Ris,300
24
22
  TB2J/myTB.py,sha256=ok_B4my29bOIghMSZfx0Es6G8FaXaIiLP4gPxTdSj00,17659
25
23
  TB2J/orbmap.py,sha256=RCMJkOPGbfPrcZzcc5ia1ZMKBQWxGcyj8W1ve8BJaEw,6669
26
- TB2J/patch.py,sha256=Z3KZklID9U8zKuk6Ek1Tq95JcY3eT4770dsdcXz6mAA,1067
27
24
  TB2J/pauli.py,sha256=zOELm7Vgxw6SMaO5l7qVWx1pBKZt25RLnEpnVM3dz_0,4545
28
25
  TB2J/pert.py,sha256=RaCJfewl0doht4cjAnzzGKe-uj2le4aqe0iPKFrq9fo,1192
29
26
  TB2J/plot.py,sha256=AnFIFWE2vlmj7Z6f_7-dX_O1stJN-qbuiurPj43dUCM,4104
30
27
  TB2J/rotate_atoms.py,sha256=Dwptn-wdDW4zYzjYb95yxTzuZOe9WPuLjh3d3-YcSs0,3277
31
28
  TB2J/rotate_siestaDM.py,sha256=eR97rspdrRaK9YTwQwUKfobI0S9UnEcbEZ2f5IgR7Tk,1070
32
29
  TB2J/sisl_wrapper.py,sha256=A5x1-tt8efUSPeGY5wM5m6-pJYQFXTCzQHVqD6RBa2g,14792
33
- TB2J/supercell.py,sha256=4hgLGPBLRUDhtD-eF29v46ex7fHdkH-OENjS2wGLFww,19588
34
30
  TB2J/tensor_rotate.py,sha256=4-DfT_Mg5e40fbd74M5W0D5DqmUq-kVOOLDkkkI834A,8083
35
31
  TB2J/utest.py,sha256=z_ahi7tpHQF9WlHNQihcQ7qzfezRJQXQt28eB1X_z64,3897
36
32
  TB2J/utils.py,sha256=DHkc7BK0KUGesfoAv1OxMgIw_iZzcFXh--3ybsFSd_c,12535
@@ -51,7 +47,6 @@ TB2J/external/p_tqdm.py,sha256=ug1jy3-43r8iW7bC37xzPSIe0EjYKH_GUluGzMiQiDw,5831
51
47
  TB2J/io_exchange/__init__.py,sha256=KfGHum7B8E4G_KKfillqw0lErtoyKEuFUUttHLs-mg4,32
52
48
  TB2J/io_exchange/io_exchange.py,sha256=RxCZ7OOxhiIzGrIidCOqxNbgLsrHUfCqDVinMvrPdmI,19354
53
49
  TB2J/io_exchange/io_multibinit.py,sha256=8PDmWxzGuv-GwJosj2ZTmiyNY_duFVWJ4ekCuSqGdd8,6739
54
- TB2J/io_exchange/io_pickle.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
50
  TB2J/io_exchange/io_tomsasd.py,sha256=NqkAC1Fl-CUnFA21eBzSy_S5F_oeQFJysw4UukQbN8o,4173
56
51
  TB2J/io_exchange/io_txt.py,sha256=BMr1eSILlKpgtjvDx7uw2VMAkEKSvGEPNxpaT_zev0I,10547
57
52
  TB2J/io_exchange/io_uppasd.py,sha256=bI4iPEgnK4TvCZNvb6x2xYXgjW7pEehCqmcizy2pqFU,3301
@@ -64,10 +59,8 @@ TB2J/mathutils/rotate_spin.py,sha256=XtfwHGfIqI9nRYZcCd_yQ3Ud1AXVJj9fwqIHloMcaCs
64
59
  TB2J/spinham/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
60
  TB2J/spinham/base_parser.py,sha256=oQRHvFE_BlUtTaTZykKgvicu40oXcbICB-D1aAt-qlA,2196
66
61
  TB2J/spinham/constants.py,sha256=y4-hRyl5EAR42k24Oa5XhAsUQtKVn1MAgyqNf-p3PrM,762
67
- TB2J/spinham/h_matrix.py,sha256=MfHIz6RViKkEB3Mu-WcwNx5uk7A5sjAlbqVG9wYA4xk,2784
68
62
  TB2J/spinham/hamiltonian.py,sha256=OfsjlGIgFwpXaohopZcgPamSfjm3X46_zc245eyTr_A,16607
69
63
  TB2J/spinham/hamiltonian_terms.py,sha256=7e84tfEjvAfZltUkrSWi1sUEiW_itLKy83lxi5iBpcQ,9714
70
- TB2J/spinham/obtain_J.py,sha256=sg8tiCRRLEN57Olb3MHIuqkDhAkmu-w87AkM00ylXtA,2401
71
64
  TB2J/spinham/plot.py,sha256=tLLNqFAATVrP1kmSVLPKzn686i-CUyqu4qgOcs-okHI,6599
72
65
  TB2J/spinham/qsolver.py,sha256=Sr9I3aGfVNYn5wzwPx1QonHe6ZZUXBAujWRa7nTA5u4,4986
73
66
  TB2J/spinham/spin_api.py,sha256=oN3AKg1WQl0YzR4f5ealcJOaVoAy8d7HodIwrbXvQeY,2219
@@ -76,18 +69,18 @@ TB2J/spinham/supercell.py,sha256=y17uUC6r3gQb278FhxIW4CABihfLTvKFj6flyXrCPR8,122
76
69
  TB2J/wannier/__init__.py,sha256=7ojCbM84PYv1X1Tbo4NHI-d3gWmQsZB_xiYqbfxVV1E,80
77
70
  TB2J/wannier/w90_parser.py,sha256=dbd63LuKyv2DVUzqRINGsbDzEsOxsQyE8_Ear_LQIRg,4620
78
71
  TB2J/wannier/w90_tb_parser.py,sha256=qt8pnuprmPp9iIAYwPkPbmEzk6ZPgMq2xognoQp7vwc,4610
79
- TB2J-0.9.0.2.data/scripts/TB2J_downfold.py,sha256=i4BVqnpDdgrX_amookVWeLGefGBn-qeAutWiwuY9SfQ,2099
80
- TB2J-0.9.0.2.data/scripts/TB2J_eigen.py,sha256=Qs9v2hnMm2Tpfoa4h53muUKty2dZjwx8948MBoQooNg,1128
81
- TB2J-0.9.0.2.data/scripts/TB2J_magnon.py,sha256=q7UwAmorRcFNk4tfE7gl_ny05l6p7pbD9Wm_LkIpKEw,3101
82
- TB2J-0.9.0.2.data/scripts/TB2J_magnon_dos.py,sha256=TMXQvD2dIbO5FZ4tUMmxJgCgH2O2hDAPUNfEKO4z-x4,110
83
- TB2J-0.9.0.2.data/scripts/TB2J_merge.py,sha256=y834SF4rIRn1L1ptkhczvavQpC-8Px6DTmDOOSaq_DE,1854
84
- TB2J-0.9.0.2.data/scripts/TB2J_rotate.py,sha256=zgiDFuYZNmzKK0rwDmTaYD2OpRlmKA_VGeBx83w2Xwc,873
85
- TB2J-0.9.0.2.data/scripts/TB2J_rotateDM.py,sha256=kCvF7gotuqAX1VnJ06cwfVm7RrhrdtiV5v7d9P2Pn_E,567
86
- TB2J-0.9.0.2.data/scripts/abacus2J.py,sha256=M4B07lvTCDczTPTqvnDh_PERzCARAd09TLKv4aIdSQM,4408
87
- TB2J-0.9.0.2.data/scripts/siesta2J.py,sha256=hBzS7ZgoHM3oXlTCQd-xVA07Ks2FiIwyRpQWUFITRPE,4303
88
- TB2J-0.9.0.2.data/scripts/wann2J.py,sha256=2t2hWwyELskYCwkGDziCgiIAnfr6odLLJ6cQBJ2RQwQ,5714
89
- TB2J-0.9.0.2.dist-info/LICENSE,sha256=CbZI-jyRTjiqIcWa244cRSHJdjjtUNqGR4HeJkgEwJw,1332
90
- TB2J-0.9.0.2.dist-info/METADATA,sha256=WhFy-Jej3lhp1tyTWrIr_J4hbutGY_DD1S5zJk1YqYk,1420
91
- TB2J-0.9.0.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
92
- TB2J-0.9.0.2.dist-info/top_level.txt,sha256=whYa5ByLYhl5XnTPBHSWr-IGD6VWmr5Ql2bye2qwV_s,5
93
- TB2J-0.9.0.2.dist-info/RECORD,,
72
+ TB2J-0.9.0.3.data/scripts/TB2J_downfold.py,sha256=i4BVqnpDdgrX_amookVWeLGefGBn-qeAutWiwuY9SfQ,2099
73
+ TB2J-0.9.0.3.data/scripts/TB2J_eigen.py,sha256=Qs9v2hnMm2Tpfoa4h53muUKty2dZjwx8948MBoQooNg,1128
74
+ TB2J-0.9.0.3.data/scripts/TB2J_magnon.py,sha256=q7UwAmorRcFNk4tfE7gl_ny05l6p7pbD9Wm_LkIpKEw,3101
75
+ TB2J-0.9.0.3.data/scripts/TB2J_magnon_dos.py,sha256=TMXQvD2dIbO5FZ4tUMmxJgCgH2O2hDAPUNfEKO4z-x4,110
76
+ TB2J-0.9.0.3.data/scripts/TB2J_merge.py,sha256=y834SF4rIRn1L1ptkhczvavQpC-8Px6DTmDOOSaq_DE,1854
77
+ TB2J-0.9.0.3.data/scripts/TB2J_rotate.py,sha256=zgiDFuYZNmzKK0rwDmTaYD2OpRlmKA_VGeBx83w2Xwc,873
78
+ TB2J-0.9.0.3.data/scripts/TB2J_rotateDM.py,sha256=kCvF7gotuqAX1VnJ06cwfVm7RrhrdtiV5v7d9P2Pn_E,567
79
+ TB2J-0.9.0.3.data/scripts/abacus2J.py,sha256=M4B07lvTCDczTPTqvnDh_PERzCARAd09TLKv4aIdSQM,4408
80
+ TB2J-0.9.0.3.data/scripts/siesta2J.py,sha256=hBzS7ZgoHM3oXlTCQd-xVA07Ks2FiIwyRpQWUFITRPE,4303
81
+ TB2J-0.9.0.3.data/scripts/wann2J.py,sha256=2t2hWwyELskYCwkGDziCgiIAnfr6odLLJ6cQBJ2RQwQ,5714
82
+ TB2J-0.9.0.3.dist-info/LICENSE,sha256=CbZI-jyRTjiqIcWa244cRSHJdjjtUNqGR4HeJkgEwJw,1332
83
+ TB2J-0.9.0.3.dist-info/METADATA,sha256=Vj1aJnognG0_1yHXRKsFzGEce2uxyCA6xo7t7KCE8jQ,1420
84
+ TB2J-0.9.0.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
85
+ TB2J-0.9.0.3.dist-info/top_level.txt,sha256=whYa5ByLYhl5XnTPBHSWr-IGD6VWmr5Ql2bye2qwV_s,5
86
+ TB2J-0.9.0.3.dist-info/RECORD,,
TB2J/MAE.py DELETED
@@ -1,188 +0,0 @@
1
- import numpy as np
2
- from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
3
- from TB2J.mathutils.rotate_spin import rotate_Matrix_from_z_to_axis
4
- from TB2J.kpoints import monkhorst_pack
5
- from TB2J.mathutils.fermi import fermi
6
- from TB2J.mathutils.kR_convert import R_to_k
7
- from scipy.linalg import eigh
8
- from copy import deepcopy
9
- from scipy.spatial.transform import Rotation
10
- import matplotlib.pyplot as plt
11
- from pathlib import Path
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
18
-
19
-
20
- def get_occupation(evals, kweights, nel, width=0.1):
21
- occ = Occupations(nel=nel, width=width, wk=kweights, nspin=2)
22
- return occ.occupy(evals)
23
-
24
-
25
- def get_density_matrix(evals=None, evecs=None, kweights=None, nel=None, width=0.1):
26
- occ = get_occupation(evals, kweights, nel, width=width)
27
- rho = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
28
- return rho
29
-
30
-
31
- class MAE:
32
- def __init__(self, model, kmesh, gamma=True, width=0.1, nel=None):
33
- self.model = model
34
- if nel is not None:
35
- self.model.nel = nel
36
- self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
37
- self.kweights = np.ones(len(self.kpts), dtype=float) / len(self.kpts)
38
- self.width = width
39
-
40
- def get_band_energy(self):
41
- evals, evecs = self.model.solve_all(self.kpts)
42
- occ = get_occupation(evals, self.kweights, self.model.nel, width=self.width)
43
- eband = np.sum(evals * occ * self.kweights[:, np.newaxis])
44
- return eband
45
-
46
- def calc_ref(self):
47
- # calculate the Hk_ref, Sk_ref, Hk_soc_ref, and rho_ref
48
- self.Sk_ref = R_to_k(self.kpts, self.model.Rlist, self.model.SR)
49
- self.Hk_xc_ref = R_to_k(self.kpts, self.model.Rlist, self.model._HR_copy)
50
- self.Hk_soc_ref = R_to_k(self.kpts, self.model.Rlist, self.model.HR_soc)
51
- self.rho_ref = np.zeros(
52
- (len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
53
- )
54
-
55
- evals = np.zeros((len(self.kpts), self.model.nbasis), dtype=float)
56
- evecs = np.zeros(
57
- (len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
58
- )
59
-
60
- for ik, kpt in enumerate(self.kpts):
61
- # evals, evecs = eigh(self.Hk_xc_ref[ik]+self.Hk_soc_ref[ik], self.Sk_ref[ik])
62
- evals[ik], evecs[ik] = eigh(self.Hk_xc_ref[ik], self.Sk_ref[ik])
63
- occ = get_occupation(
64
- evals, self.kweights, self.model.nel, width=self.model.width
65
- )
66
- # occ = fermi(evals, self.model.efermi, width=self.model.width)
67
- self.rho_ref = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
68
-
69
- def get_band_energy_vs_angles(
70
- self,
71
- thetas,
72
- phis,
73
- ):
74
- es = []
75
- # es2 = []
76
- # e,rho = self.model.get_band_energy(dm=True)
77
- # self.calc_ref()
78
- # thetas = np.linspace(*angle_range, npoints)
79
- nangles = len(thetas)
80
- for i in tqdm.trange(nangles):
81
- theta = thetas[i]
82
- phi = phis[i]
83
- self.model.set_Hsoc_rotation_angle([theta, phi])
84
- e = self.get_band_energy()
85
- es.append(e)
86
- # es2.append(e2)
87
- return es
88
-
89
-
90
- def get_model_energy(model, kmesh, gamma=True):
91
- ham = MAE(model, kmesh, gamma=gamma)
92
- return ham.get_band_energy()
93
-
94
-
95
- def abacus_get_MAE(
96
- path_nosoc, path_soc, kmesh, thetas, psis, gamma=True, outfile="MAE.txt", nel=None
97
- ):
98
- """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
- parser = AbacusSplitSOCParser(
100
- outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
101
- )
102
- model = parser.parse()
103
- ham = MAE(model, kmesh, gamma=gamma)
104
- es = ham.get_band_energy_vs_angles(thetas, psis)
105
- if outfile:
106
- with open(outfile, "w") as f:
107
- f.write("#theta, psi, energy\n")
108
- for theta, psi, e in zip(thetas, psis, es):
109
- f.write(f"{theta:5.3f}, {psi:5.3f}, {e:10.9f}\n")
110
- return es
111
-
112
-
113
- def siesta_get_MAE(fdf_fname, kmesh, thetas, phis, gamma=True, outfile="MAE.txt"):
114
- """ """
115
- model= SislParser(fdf_fname=fdf_fname, read_H_soc=True).get_model()
116
- ham = MAE(model, kmesh, gamma=gamma)
117
- es = ham.get_band_energy_vs_angles(thetas, phis)
118
- if outfile:
119
- with open(outfile, "w") as f:
120
- f.write("#theta, psi, energy\n")
121
- for theta, psi, e in zip(thetas, phis, es):
122
- #f.write(f"{theta}, {psi}, {e}\n")
123
- f.write(f"{theta:5.3f}, {psi:5.3f}, {e:10.9f}\n")
124
- return es
125
-
126
-
127
- def test_AbacusSplitSOCWrapper():
128
- # path = Path("~/projects/2D_Fe").expanduser()
129
- path = Path("~/projects/TB2Jflows/examples/2D_Fe/Fe_z").expanduser()
130
- outpath_nosoc = f"{path}/soc0/OUT.ABACUS"
131
- outpath_soc = f"{path}/soc1/OUT.ABACUS"
132
- parser = AbacusSplitSOCParser(
133
- outpath_nosoc=outpath_nosoc, outpath_soc=outpath_soc, binary=False
134
- )
135
- model = parser.parse()
136
- kmesh = [6, 6, 1]
137
-
138
- r = MAE(model, kmesh, gamma=True)
139
- # thetas, es = r.get_band_energy_vs_theta(angle_range=(0, np.pi*2), rotation_axis="z", initial_direction=(1,0,0), npoints=21)
140
- thetas, es, es2 = r.get_band_energy_vs_theta(
141
- angle_range=(0, np.pi),
142
- rotation_axis="y",
143
- initial_direction=(0, 0, 1),
144
- npoints=11,
145
- )
146
- # print the table of thetas and es, es2
147
- for theta, e, e2 in zip(thetas, es, es2):
148
- print(f"{theta=}, {e=}, {e2=}")
149
-
150
- plt.plot(thetas / np.pi, es - es[0], marker="o")
151
- plt.plot(thetas / np.pi, es2 - es2[0], marker=".")
152
- plt.savefig("E_along_z_x_z.png")
153
- plt.show()
154
-
155
-
156
- def abacus_get_MAE_cli():
157
- import argparse
158
-
159
- parser = argparse.ArgumentParser(
160
- description="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. "
161
- )
162
- parser.add_argument("path_nosoc", type=str, help="Path to the calculation with ")
163
- parser.add_argument("path_soc", type=str, help="Path to the SOC calculation")
164
- parser.add_argument("thetas", type=float, nargs="+", help="Thetas")
165
- parser.add_argument("psis", type=float, nargs="+", help="Phis")
166
- parser.add_argument("kmesh", type=int, nargs=3, help="K-mesh")
167
- parser.add_argument(
168
- "--gamma", action="store_true", help="Use Gamma centered kpoints"
169
- )
170
- parser.add_argument(
171
- "--outfile",
172
- type=str,
173
- help="The angles and the energey will be saved in this file.",
174
- )
175
- args = parser.parse_args()
176
- abacus_get_MAE(
177
- args.path_nosoc,
178
- args.path_soc,
179
- args.kmesh,
180
- args.thetas,
181
- args.psis,
182
- gamma=args.gamma,
183
- outfile=args.outfile,
184
- )
185
-
186
-
187
- if __name__ == "__main__":
188
- abacus_get_MAE_cli()
TB2J/cut_cell.py DELETED
@@ -1,82 +0,0 @@
1
- import numpy as np
2
- from TB2J.supercell import find_primitive_cell, map_to_primitive
3
- from TB2J.io_exchange.io_exchange import SpinIO, gen_distance_dict
4
-
5
-
6
- def cut_cell(path, output_path, sc_matrix, origin_atom_id, thr=1e-5):
7
- """
8
- Cut the exchange parameters
9
- :param path: the original TB2J_results path
10
- :param output_path: the output path.
11
- :param sc_matrix: the matrix which maps the primitive cell to supercell.
12
- :param origin: the origin of the primitive cell.
13
- :param thr: the atoms which the reduced position is within -thr to 1.0+thr are considered as inside the primitive atoms
14
- :returns:
15
- """
16
- sc_matrix = np.asarray(sc_matrix, dtype=int)
17
- sc_excparams = SpinIO.load_pickle(path=path, fname='TB2J.pickle')
18
- sc_atoms = sc_excparams.atoms
19
- uc_atoms, ids = find_primitive_cell(sc_atoms,
20
- sc_matrix,
21
- origin_atom_id=origin_atom_id,
22
- thr=thr,
23
- perfect=False)
24
- uc_charges = sc_excparams.charges[ids]
25
- uc_spinat = sc_excparams.spinat[ids]
26
- indmap, Rmap = map_to_primitive(sc_atoms, uc_atoms)
27
-
28
- # TODO index_spin: {iatom: ispin}
29
-
30
- # list of iatom for each spin index.
31
- uc_index_spin = [sc_excparams.index_spin[i] for i in ids]
32
-
33
- uc_ind_atoms = {}
34
- for iatom, ispin in enumerate(uc_index_spin):
35
- if ispin >= 0:
36
- uc_ind_atoms[ispin] = iatom
37
-
38
- uc_Jdict = {}
39
- uc_Rset = set()
40
- for key, val in sc_excparams.exchange_Jdict.items():
41
- R, ispin, jspin = key
42
- iatom = sc_excparams.ind_atoms[ispin]
43
- jatom = sc_excparams.ind_atoms[jspin]
44
- uc_ispin = uc_index_spin[indmap[iatom]]
45
- uc_jspin = uc_index_spin[indmap[jatom]]
46
- uc_R = R @ sc_matrix + Rmap[jatom] - Rmap[iatom]
47
- uc_R = tuple(uc_R)
48
- if iatom in ids:
49
- #print(f"{iatom=}, {indmap[iatom]=},{uc_ispin=}, {uc_jspin=}, {uc_R=} ")
50
- uc_Jdict[(uc_R, uc_ispin, uc_jspin)] = val
51
- uc_Rset.add(uc_R)
52
-
53
- uc_distance_dict = gen_distance_dict(uc_ind_atoms, uc_atoms, list(uc_Rset))
54
-
55
- assert sc_excparams.colinear, "Cut supercell for non-collinear spin is not yet implemented."
56
-
57
- uc_exc = SpinIO(uc_atoms,
58
- spinat=uc_spinat,
59
- charges=uc_charges,
60
- index_spin=uc_index_spin,
61
- colinear=sc_excparams.colinear,
62
- distance_dict=uc_distance_dict,
63
- exchange_Jdict=uc_Jdict,
64
- description="Cutted")
65
-
66
- uc_exc.write_all(output_path)
67
-
68
-
69
- def run_cut_cell(
70
- path="TB2J_results",
71
- output_path="./TB2J_cutted",
72
- sc_matrix=np.array([[1, 1, 0], [-1, 1, 0], [0, 0, 2]]),
73
- ):
74
- cut_cell(path,
75
- output_path,
76
- np.array(sc_matrix),
77
- origin_atom_id=0,
78
- thr=1e-19)
79
-
80
-
81
- if __name__ == "__main__":
82
- run_cut_cell()
File without changes
TB2J/patch.py DELETED
@@ -1,50 +0,0 @@
1
- import types
2
- from unittest import mock
3
-
4
- class A(object):#but seems to work for old style objects too
5
- def funcx(self,x):
6
- print("x1=",x)
7
- print("called from", self)
8
-
9
- def method(self,x):
10
- print("xmethod=",x)
11
- print("called from", self)
12
-
13
- def patch_me(target):
14
- def method(target,x):
15
- print("x=",x)
16
- print("called from", target)
17
- target.method = types.MethodType(method,target)
18
-
19
- def method(self,x):
20
- print("x=",x)
21
- print("called from", self)
22
-
23
- @mock.patch("__main__.A")
24
- def funcx(self,x):
25
- print("new x=",x)
26
- print("called from", self)
27
-
28
- A.method=method
29
- #add more if needed
30
- a = A()
31
- print(A.__dict__)
32
- print(a)
33
- #out: <__main__.A object at 0x2b73ac88bfd0>
34
-
35
- @mock.patch("__main__.a")
36
- def funcx(self,x):
37
- print("x=",x)
38
- print("called from", self)
39
-
40
- a.funcx(3)
41
- patch_me(a) #patch instance
42
- a.method=method
43
- #a.method(5)
44
- #out: x= 5
45
- #out: called from <__main__.A object at 0x2b73ac88bfd0>
46
- patch_me(A)
47
-
48
- a.method(6) #can patch class too
49
- #out: x= 6
50
- #out: called from <class '__main__.A'>
TB2J/spinham/h_matrix.py DELETED
@@ -1,68 +0,0 @@
1
- import numpy as np
2
- import matplotlib.pyplot as plt
3
- import aiida
4
- from aiida_tb2j.data import ExchangeData
5
-
6
- def plot_dispersion(bands, kpoint_labels, color='blue', title=None):
7
-
8
- fig, axs = plt.subplots(1, 1, constrained_layout=True)
9
- fig.set_size_inches(6, 6/1.618)
10
-
11
- '''
12
- Plot the bands
13
- '''
14
- kpoints = np.arange(len(bands))
15
- axs.plot(kpoints, bands, color=color, linewidth=1.5)
16
-
17
- '''
18
- Plot the symmetry points
19
- '''
20
- bmin = bands.min(); bmax = bands.max()
21
- ymin = bmin - 0.05*np.abs(bmin-bmax); ymax = bmax + 0.05*np.abs(bmax-bmin);
22
- axs.set_xticks(kpoint_labels[0], kpoint_labels[1], fontsize=10)
23
- axs.vlines(x=kpoint_labels[0], ymin=ymin, ymax=ymax, color='black', linewidth=0.5)
24
- axs.set_xlim([0, len(kpoints)])
25
- axs.set_ylim([ymin, ymax])
26
-
27
- if title is not None:
28
- plt.title(title, fontsize=10)
29
-
30
- plt.show()
31
-
32
-
33
- if __name__ == "__main__":
34
-
35
- from argparse import ArgumentParser
36
-
37
- parser = ArgumentParser()
38
- parser.add_argument('-f', '--pickle_filename', type=str, help="Path of the 'TB2J.pickle' file.", required=True)
39
- args = parser.parse_args()
40
-
41
- '''
42
- Right now the implementation depends on AiiDA and so we must create and load an AiiDA profile,
43
- even if we do not store any information on a data base.
44
- '''
45
- aiida.load_profile()
46
- '''
47
- Create an ExchangeData object with the informations from the TB2J.pickle file
48
- '''
49
- exchange = ExchangeData.load_tb2j(pickle_file=args.pickle_filename, isotropic=False, pbc=(True, True, True))
50
- '''
51
- Compute the magnon band structure along a high symmetry path generated with
52
- the ASE package. The informations is stored in an AiiDA BandsData object.
53
- Here tol is the symmetry tolerance to determine the space group of the system.
54
- They are in units of eV
55
- '''
56
- magnon_data = exchange.get_magnon_bands(npoints=300, tol=1e-1, with_DMI=True, with_Jani=True)
57
- magnon_bands = 1000*magnon_data.get_bands() # Convert to meV
58
- raw_labels = [(k, '$\Gamma$') if s == 'GAMMA' else (k, s) for k, s in magnon_data.labels]
59
- kpoint_labels = list( zip( *raw_labels ) )
60
- plot_dispersion(magnon_bands, kpoint_labels, color='blue', title='Magnon Bands')
61
- '''
62
- We can also obtain the dynamical matrix h instead of the actual magnon bands. The result
63
- is stored in a numpy array with shape (number of kpoints, 2*natoms, 2*natoms)
64
- '''
65
- kpoints = magnon_data.get_kpoints() # The shape of the kpoints must be (nkpoints, 3)
66
- h_matrix = 1000*exchange._H_matrix(kpoints, with_DMI=True, with_Jani=True) # Convert to meV
67
- h_dispersion = np.linalg.eigvalsh(h_matrix) # We can also get the eigenvectors with np.linalg.eigh
68
- plot_dispersion(h_dispersion, kpoint_labels, color='red', title='h matrix dispersion')
TB2J/spinham/obtain_J.py DELETED
@@ -1,79 +0,0 @@
1
- import numpy as np
2
- from aiida_tb2j.data import ExchangeData
3
- from aiida_tb2j.data.exchange import get_rotation_arrays
4
- from itertools import combinations_with_replacement
5
-
6
- ux, uy, uz = np.eye(3).reshape((3, 1, 3))
7
-
8
- def combine_arrays(u, v):
9
-
10
- return np.concatenate([u*v, np.roll(u, -1, axis=-1)*v, np.roll(v, -1, axis=-1)*u], axis=-1)
11
-
12
- def get_coefficients(magmoms, indices):
13
-
14
- i, j = indices
15
-
16
- U, V = zip(*[get_rotation_arrays(magmoms, u=u) for u in [ux, uy, uz]])
17
- U = np.stack(U).swapaxes(0, 1)
18
- V = np.stack(V).swapaxes(0, 1)
19
-
20
- uc = combine_arrays(U[i], U[j].conj())
21
- ur = combine_arrays(U[i], U[j])
22
- uc2 = combine_arrays(U[i].conj(), U[j])
23
- u = np.concatenate([uc, ur, uc2], axis=1)
24
-
25
- return u, V
26
-
27
- def get_C(H0, u, V):
28
-
29
- n = int(H0.shape[-1]/2)
30
- upi = np.triu_indices(n)
31
- dig = np.diag_indices(n)
32
-
33
- i, j = upi
34
- AB0 = H0[:, [i, i, i+n], [j, j+n, j+n]]
35
- AB0 = np.swapaxes(AB0, 0, 2).reshape(len(i), 9)
36
- J0_flat = np.linalg.solve(u, AB0)
37
-
38
- J0 = np.empty((n, n, 3, 3), dtype=complex)
39
- J0[*upi] = J0_flat[:, [0, 6, 5, 3, 1, 7, 8, 4, 2]].reshape(-1, 3, 3)
40
- J0 += J0.swapaxes(0, 1)
41
- J0[*dig] = 0.0
42
-
43
- C = np.array([np.diag(a) for a in np.einsum('imx,ijxy,jmy->mi', V, 2*J0, V)])
44
-
45
- return C
46
-
47
- def get_J(H, kpoints, exchange):
48
-
49
- n = int(H.shape[-1]/2)
50
- upi = np.triu_indices(n)
51
- dig = np.diag_indices(n)
52
- i, j = upi
53
-
54
- magmoms = exchange.magmoms()[np.unique(exchange.pairs)]
55
- magmoms /= np.linalg.norm(magmoms, axis=-1).reshape(-1, 1)
56
- u, V = get_coefficients(magmoms, indices=upi)
57
-
58
- H0 = np.stack([1000*exchange._H_matrix(kpoints=np.zeros((1, 3)), with_DMI=True, with_Jani=True, u=u) for u in [ux, uy, uz]])[:, 0, :, :]
59
- C = get_C(H0, u, V)
60
- H[:, :, :n, :n] += C.reshape(3, 1, n, n)
61
- H[:, :, n:, n:] += C.reshape(3, 1, n, n)
62
-
63
- AB = H[:, :, [i, i, i+n], [j, j+n, j+n]]
64
- AB[:, :, 2, :] = AB[:, ::-1, 2, :]
65
- AB = np.moveaxis(AB, [2, 3], [1, 0]).reshape(len(i), 9, -1)
66
-
67
- vectors = exchange.get_vectors()
68
- exp_summand = np.exp( -2j*np.pi*vectors @ kpoints.T )
69
- nAB = np.einsum('nik,ndk->nid', AB, exp_summand) / len(kpoints)
70
-
71
- ii = np.where(i == j)
72
- i0 = np.where(np.linalg.norm(vectors, axis=-1) == 0.0)
73
- J = np.linalg.solve(u, nAB).swapaxes(1, 2)
74
- J = J[:, :, [0, 6, 5, 3, 1, 7, 8, 4, 2]].reshape(len(i), -1, 3, 3)
75
- J *= -1
76
- J[ii] *= 2
77
- J[i0] *= 0
78
-
79
- return J
TB2J/supercell.py DELETED
@@ -1,532 +0,0 @@
1
- """
2
- A helper class for building supercells
3
- """
4
- import numpy as np
5
- from collections import OrderedDict, defaultdict
6
- from itertools import product
7
- from functools import lru_cache
8
- from ase.build import make_supercell
9
- from ase.atoms import Atoms
10
-
11
-
12
- def close_to_int(x, tol=1e-4):
13
- return np.allclose(x, np.round(x), atol=tol)
14
-
15
-
16
- class SupercellMaker(object):
17
-
18
- def __init__(self, sc_matrix, center=False):
19
- """
20
- a helper class for making supercells.
21
- sc_matrix, supercell matrix. sc_matrix .dot. unitcell = supercell
22
- """
23
- sc_matrix = np.array(sc_matrix, dtype=int)
24
- if len(sc_matrix.flatten()) == 3:
25
- sc_matrix = np.diag(sc_matrix)
26
- elif sc_matrix.shape == (3, 3):
27
- pass
28
- else:
29
- raise ValueError('sc_matrix should be 3 or 3*3 matrix')
30
- self.sc_matrix = sc_matrix
31
- self.center = center
32
- if center:
33
- self.shift = np.array([0.5, 0.5, 0.5])
34
- else:
35
- self.shift = np.zeros(3, dtype=float)
36
- self.inv_scmat = np.linalg.inv(self.sc_matrix.T)
37
- self.build_sc_vec()
38
- self.ncell = int(round(abs(np.linalg.det(sc_matrix))))
39
-
40
- def to_red_sc(self, x):
41
- return np.dot(self.inv_scmat, x) + self.shift
42
-
43
- def build_sc_vec(self):
44
- eps_shift = np.sqrt(
45
- 2.0) * 1.0E-8 # shift of the grid, so to avoid double counting
46
- #max_R = np.max(np.abs(self.sc_matrix)) * 3
47
- if self.center:
48
- minr = -0.5
49
- maxr = 0.5
50
- else:
51
- minr = 0.0
52
- maxr = 1.0
53
- sc_vec = []
54
- newcell = self.sc_matrix
55
- scorners_newcell = np.array([[0., 0., 0.], [0., 0., 1.], [0., 1., 0.],
56
- [0., 1., 1.], [1., 0., 0.], [1., 0., 1.],
57
- [1., 1., 0.], [1., 1., 1.]])
58
- corners = np.dot(scorners_newcell - self.shift, newcell)
59
- scorners = corners
60
- #rep = np.ceil(scorners.ptp(axis=0)).astype('int') + 1
61
- minrep = np.ceil(np.min(scorners, axis=0)).astype('int')
62
- maxrep = np.ceil(np.max(scorners, axis=0)).astype('int') + 1
63
-
64
- # sc_vec: supercell vector (map atom from unit cell to supercell)
65
- # for vec in product(range(rep[0]), range(rep[1]), range(rep[2])):
66
- for vec in product(range(minrep[0], maxrep[0]),
67
- range(minrep[1], maxrep[1]),
68
- range(minrep[2], maxrep[2])):
69
- # compute reduced coordinates of this candidate vector in the super-cell frame
70
- tmp_red = self.to_red_sc(vec)
71
- # check if in the interior
72
- if (not (tmp_red <= -eps_shift).any()) and (
73
- not (tmp_red > 1.0 - eps_shift).any()):
74
- sc_vec.append(np.array(vec))
75
-
76
- # number of times unit cell is repeated in the super-cell
77
- num_sc = len(sc_vec)
78
-
79
- # check that found enough super-cell vectors
80
- if int(round(np.abs(np.linalg.det(self.sc_matrix)))) != num_sc:
81
- raise Exception(
82
- "\n\nSuper-cell generation failed! Wrong number of super-cell vectors found."
83
- )
84
-
85
- sc_vec = np.array(sc_vec)
86
- self.sc_vec = np.array(sc_vec)
87
- svtuple = (tuple(s) for s in sc_vec)
88
- self.sc_vec_dict = dict(zip(svtuple, range(sc_vec.shape[0])))
89
-
90
- def get_R(self):
91
- return self.sc_vec
92
-
93
- @property
94
- def R_sc(self):
95
- return self.sc_vec
96
-
97
- def sc_cell(self, cell):
98
- cell = np.array(cell)
99
- if len(cell.flatten()) == 3:
100
- cell = np.diag(cell)
101
- return np.dot(self.sc_matrix, cell)
102
-
103
- def sc_pos(self, positions, return_R=False):
104
- """
105
- pos -> pos in supercell (reduced.)
106
- """
107
- sc_pos = []
108
- sc_R = []
109
- for cur_sc_vec in self.sc_vec: # go over all super-cell vectors
110
- for pos in positions:
111
- # shift orbital and compute coordinates in
112
- # reduced coordinates of super-cell
113
- sc_pos.append(self.to_red_sc(pos + cur_sc_vec))
114
- sc_R.append(cur_sc_vec)
115
- if return_R:
116
- return sc_pos, sc_R
117
- else:
118
- return sc_pos
119
-
120
- def sc_trans_invariant(self, q, return_R=False):
121
- """
122
- translation invariant quantities. Like on-site energy of tight binding,
123
- chemical symbols, magnetic moments of spin.
124
- """
125
- sc_q = []
126
- sc_R = [] # supercell R
127
- for cur_sc_vec in self.sc_vec: # go over all super-cell vectors
128
- for qitem in q:
129
- sc_q.append(qitem)
130
- sc_R.append(cur_sc_vec)
131
- if return_R:
132
- return sc_q, sc_R
133
- else:
134
- return sc_q
135
-
136
- def sc_trans_kvector(self, x, kpt, phase=0.0, real=False):
137
- """
138
- x is a vector of quantities inside the primitive cell.
139
- qpoint is the wavevector
140
- phase
141
- x_sc= x * exp(i(qR + phase))
142
-
143
- Note: if x is a 2D m*n array, the first m*n block is the primitive cell.
144
- [block1, block2, block3, ... block_ncell]
145
- """
146
- factor = self.phase_factor(kpt, phase=phase)
147
- ret = np.kron(factor, x)
148
- if real:
149
- ret = np.real(ret)
150
- return ret
151
-
152
- def Rvector_for_each_element(self, n_ind=1):
153
- """
154
- repeat the R_sc vectors.
155
- """
156
- return np.kron(self.sc_vec, np.ones((n_ind, 1)))
157
-
158
- def sc_index(self, indices, n_ind=None):
159
- """
160
- Note that the number of indices could be inequal to the repeat period.
161
- e.g. for n_orb of orbitals, the indices of atoms iatom for each orbital.
162
- In that case, in the second unit cell (c=1 here), iatom-> iatom+n_ind,
163
- where n_ind=natoms in primitive cell.
164
- """
165
- sc_ind = []
166
- if n_ind is None:
167
- n_ind = len(indices)
168
- for c, cur_sc_vec in enumerate(
169
- self.sc_vec): # go over all super-cell vectors
170
- for ind in indices:
171
- sc_ind.append(ind + c * n_ind)
172
- return sc_ind
173
-
174
- @lru_cache(maxsize=5000)
175
- def _sc_R_to_pair_ind(self, R_plus_Rv):
176
- """
177
- R: initial R vector (e.g. R in (i, jR) pair)
178
- Rv: translation vector. (e.g. for Rv in self.sc_vec)
179
-
180
- Returns:
181
- sc_part: R in
182
- pair_ind:
183
- """
184
- R_plus_Rv = np.asarray(R_plus_Rv)
185
- sc_part = np.floor(self.to_red_sc(R_plus_Rv)) # round down!
186
- sc_part = np.array(sc_part, dtype=int)
187
- # find remaining vector in the original reduced coordinates
188
- orig_part = R_plus_Rv - np.dot(sc_part, self.sc_matrix)
189
- pair_ind1 = self.sc_vec_dict[tuple(orig_part)]
190
- return sc_part, pair_ind1
191
-
192
- def sc_jR_to_scjR(self, j, R, Rv, n_basis):
193
- """
194
- (j, R) in primitive cell to (j', R') in supercell.
195
- """
196
- Rprim, pair_ind = self._sc_R_to_pair_ind(
197
- tuple(np.array(R) + np.array(Rv)))
198
- return j + pair_ind * n_basis, tuple(Rprim)
199
-
200
- def sc_i_to_sci(self, i, ind_Rv, n_basis):
201
- return i + ind_Rv * n_basis
202
-
203
- def sc_ijR_only(self, i, j, R, n_basis):
204
- ret = []
205
- for c, cur_sc_vec in enumerate(
206
- self.sc_vec): # go over all super-cell vectors
207
- sc_part, pair_ind = self._sc_R_to_pair_ind(tuple(R + cur_sc_vec))
208
- sc_i = i + c * n_basis
209
- sc_j = j + pair_ind * n_basis
210
- ret.append((sc_i, sc_j, tuple(sc_part)))
211
- return ret
212
-
213
- def sc_jR(self, jlist, Rjlist, n_basis):
214
- sc_jlist = []
215
- sc_Rjlist = []
216
- for c, cur_sc_vec in enumerate(
217
- self.sc_vec): # go over all super-cell vectors
218
- # for i , j, ind_R, val in
219
- for j, Rj in zip(jlist, Rjlist):
220
- sc_part, pair_ind = self._sc_R_to_pair_ind(
221
- tuple(Rj + cur_sc_vec))
222
- sc_j = j + pair_ind * n_basis
223
- sc_jlist.append(sc_j)
224
- sc_Rjlist.append(tuple(sc_part))
225
- return sc_jlist, sc_Rjlist
226
-
227
- def sc_ijR(self, terms, n_basis):
228
- """
229
- # TODO very slow when supercell is large, should improve it.
230
- map Val(i, j, R) which is a funciton of (R+rj-ri) to supercell.
231
- e.g. hopping in Tight binding. exchange in heisenberg model,...
232
- Args:
233
- ========================
234
- terms: either list of [i, j, R, val] or dict{(i,j, R): val}
235
- pos: reduced positions in the unit cell.
236
- Returns:
237
- =======================
238
- """
239
- ret_dict = OrderedDict()
240
- for c, cur_sc_vec in enumerate(
241
- self.sc_vec): # go over all super-cell vectors
242
- # for i , j, ind_R, val in
243
- for (i, j, ind_R), val in terms.items():
244
- sc_part, pair_ind = self._sc_R_to_pair_ind(
245
- tuple(ind_R + cur_sc_vec))
246
- # index of "from" and "to" hopping indices
247
- sc_i = i + c * n_basis
248
- sc_j = j + pair_ind * n_basis
249
-
250
- # hi = self._hoppings[h][1] + c * self._norb
251
- # hj = self._hoppings[h][2] + pair_ind * self._norb
252
- ret_dict[(sc_i, sc_j, tuple(sc_part))] = val
253
- return ret_dict
254
-
255
- def sc_Rlist_HR(self, Rlist, HR, n_basis):
256
- """
257
- terms: H[R][i,j] = val
258
- ========================
259
- terms: either list of [i, j, R, val] or dict{(i,j, R): val}
260
- pos: reduced positions in the unit cell.
261
- Returns:
262
- =======================
263
- """
264
- sc_Rlist = []
265
- sc_HR = []
266
- for c, cur_sc_vec in enumerate(
267
- self.sc_vec): # go over all super-cell vectors
268
- # for i , j, ind_R, val in
269
- for iR, R in enumerate(Rlist):
270
- H = HR[iR]
271
- sc_part, pair_ind = self._sc_R_to_pair_ind(
272
- tuple(R + cur_sc_vec))
273
- sc_Rlist.append(sc_part)
274
- sc_val = np.zeros((n_basis * self.ncell, n_basis * self.ncell),
275
- dtype=HR.dtype)
276
- for i in range(n_basis):
277
- for j in range(n_basis):
278
- sc_i = i + c * n_basis
279
- sc_j = j + pair_ind * n_basis
280
- sc_val[sc_i, sc_j] = H[i, j]
281
- sc_HR.append(sc_val)
282
- return np.array(sc_Rlist, dtype=int), np.array(sc_HR)
283
-
284
- def sc_RHdict(self, RHdict, n_basis):
285
- """
286
- terms: H[R][i,j] = val
287
- ========================
288
- terms: either list of [i, j, R, val] or dict{(i,j, R): val}
289
- pos: reduced positions in the unit cell.
290
- Returns:
291
- =======================
292
- """
293
- sc_RHdict = defaultdict(lambda: np.zeros(
294
- (n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
295
- for c, cur_sc_vec in enumerate(
296
- self.sc_vec): # go over all super-cell vectors
297
- for R, H in RHdict.items():
298
- sc_part, pair_ind = self._sc_R_to_pair_ind(
299
- tuple(R + cur_sc_vec))
300
- ii = c * n_basis
301
- jj = pair_ind * n_basis
302
- sc_RHdict[tuple(sc_part)][ii:ii + n_basis,
303
- jj:jj + n_basis] += H
304
- return sc_RHdict
305
-
306
- def sc_RHdict_notrans(self, RHdict, n_basis, Rshift=(0, 0, 0)):
307
- sc_RHdict = defaultdict(lambda: np.zeros(
308
- (n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
309
- cur_sc_vec = np.array(Rshift)
310
- for R, H in RHdict.items():
311
- sc_part, pair_ind = self._sc_R_to_pair_ind(
312
- tuple(np.array(R) + cur_sc_vec))
313
- c = self.sc_vec_dict[Rshift]
314
- ii = c * n_basis
315
- jj = pair_ind * n_basis
316
- sc_RHdict[tuple(sc_part)][ii:ii + n_basis, jj:jj + n_basis] += H
317
- return sc_RHdict
318
-
319
- def sc_H_RpRk_notrans(self, Rplist, Rklist, n_basis, Rpprime, H):
320
- """
321
- For a given perturbation at Rp',
322
- <Rm|Rp'=Rp+Rm|Rk+Rm>
323
- =H(Rp,Rk)=<0|Rp|Rk> is a matrix of nbasis*nbasis
324
- First: Rm = Rp'-Rp, Rk+Rm = Rp'-Rp+Rm
325
- Input: Rplist, Rklist, H
326
- H: [iRg, iRk, ibasis, ibasis]
327
- """
328
- sc_RHdict = defaultdict(lambda: np.zeros(
329
- (n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
330
- for iRp, Rp in enumerate(Rplist):
331
- Rm = np.array(Rpprime) - np.array(Rp)
332
-
333
- sc_part_i, pair_ind_i = self._sc_R_to_pair_ind(tuple(np.array(Rm)))
334
- ii = pair_ind_i * n_basis
335
- if tuple(sc_part_i) == (0, 0, 0):
336
- for iRk, Rk in enumerate(Rklist):
337
- sc_part_j, pair_ind_j = self._sc_R_to_pair_ind(
338
- tuple(np.array(Rk) + np.array(Rm)))
339
- jj = pair_ind_j * n_basis
340
- sc_RHdict[tuple(sc_part_j)][ii:ii + n_basis, jj:jj +
341
- n_basis] += H[iRp, iRk, :, :]
342
- # elif tuple(sc_part_j) == (0, 0, 0):
343
- # sc_RHdict[tuple(-sc_part_j)][jj:jj + n_basis,
344
- # ii:ii + n_basis] += H[iRp, iRk, :, :].T.conj()
345
-
346
- return sc_RHdict
347
-
348
- def sc_atoms(self, atoms):
349
- """
350
- This function is compatible with ase.build.make_supercell.
351
- They should produce the same result.
352
- """
353
- sc_cell = self.sc_cell(atoms.get_cell())
354
- sc_pos = self.sc_pos(atoms.get_scaled_positions())
355
- sc_numbers = self.sc_trans_invariant(atoms.get_atomic_numbers())
356
- sc_magmoms = self.sc_trans_invariant(
357
- atoms.get_initial_magnetic_moments())
358
- return Atoms(cell=sc_cell,
359
- scaled_positions=sc_pos,
360
- numbers=sc_numbers,
361
- magmoms=sc_magmoms)
362
-
363
- def phase_factor(self, qpoint, phase=0, real=True):
364
- f = np.exp(2j * np.pi * np.einsum('i, ji -> j', qpoint, self.sc_vec) +
365
- 1j * phase)
366
- if real:
367
- f = np.real(f)
368
- return f
369
-
370
- def modulation_function_R(self, func):
371
- return [func(R) for R in self.R_sc]
372
-
373
- def _make_translate_maps(positions, basis, sc_mat, tol_r=1e-4):
374
- """
375
- find the mapping between supercell and translated cell.
376
- Returns:
377
- ===============
378
- A N * nbasis array.
379
- index[i] is the mapping from supercell to translated supercell so that
380
- T(r_i) psi = psi[indices[i]].
381
-
382
- """
383
- a1 = Atoms(symbols='H', positions=[(0, 0, 0)], cell=[1, 1, 1])
384
- sc = make_supercell(a1, self._scmat)
385
- rs = sc.get_scaled_positions()
386
-
387
- indices = np.zeros([len(rs), len(positions)], dtype='int32')
388
- for i, ri in enumerate(rs):
389
- inds = []
390
- Tpositions = positions + np.array(ri)
391
- for i_basis, pos in enumerate(positions):
392
- for j_basis, Tpos in enumerate(Tpositions):
393
- dpos = Tpos - pos
394
- if close_to_int(dpos, tol_r) and (self._basis[i_basis]
395
- == self._basis[j_basis]):
396
- indices[i, j_basis] = i_basis
397
-
398
- self._trans_rs = rs
399
- self._trans_indices = indices
400
-
401
-
402
- def smod(x):
403
- x = np.mod(x, 1)
404
- return x if x < 0.5 else x - 1
405
-
406
-
407
- smod = np.vectorize(smod)
408
-
409
-
410
- def map_to_primitive(atoms, primitive_atoms, offset=(0, 0, 0)):
411
- """
412
- Find the mapping of a supercell to a primitive cell.
413
- :param atoms: the positions of atoms
414
- :param primitive_atoms:
415
- :param offset:
416
- :param 0:
417
- :param 0):
418
-
419
- """
420
- ilist = []
421
- Rlist = []
422
- offset = np.array(offset, dtype=float)
423
- ppos = primitive_atoms.get_positions()
424
- pos = atoms.get_positions()
425
- cell = primitive_atoms.get_cell()
426
- for p in pos:
427
- found = False
428
- for i, pp in enumerate(ppos):
429
- res0 = np.linalg.solve(cell.T, p - pp)
430
- res = smod(res0)
431
- if np.linalg.norm(res) < 0.01:
432
- found = True
433
- R = res0 - res
434
- ilist.append(i)
435
- Rlist.append(R)
436
- break
437
- if not found:
438
- print("Not found")
439
- ilist.append(-1)
440
- Rlist.append([-999, -999, -999])
441
- return np.array(ilist, dtype=int), np.array(Rlist, dtype=int)
442
-
443
-
444
- def find_primitive_cell(atoms,
445
- sc_matrix,
446
- origin_atom_id=None,
447
- thr=1e-5,
448
- perfect=True):
449
- """
450
- Find a primitive cell atoms from the supercell atom structure.
451
- :param atoms: the supercell structure.
452
- :param sc_matrix: the matrix which maps the primitive cell to supercell.
453
- :param origin: the origin of the primitive cell.
454
- :param thr: the atoms which the reduced position is within -thr to 1.0+thr are considered as inside the primitive atoms
455
- :params perfect: True|False, whether the primitive cell should contains the same number of atoms .
456
- :returns: (patoms, selected)
457
- patoms: the primitive cell atoms
458
- selected: the selected indices of the atoms in the supercell.
459
- """
460
- scell = atoms.get_cell().array
461
- inv_scmat = np.linalg.inv(sc_matrix)
462
- pcell = scell@inv_scmat
463
- print(f"{inv_scmat=}")
464
-
465
- xcart = atoms.get_positions()
466
- xred = atoms.get_scaled_positions()
467
- print(xred)
468
- if origin_atom_id is not None:
469
- origin = xred[origin_atom_id]
470
- else:
471
- origin = np.zeros(3)
472
- # check if some atom is exactly at the origin.
473
- # if so, shift the positions by thr so that this atom is inside the cell
474
- # if np.any(np.linalg.norm(xred - origin[None, :], axis=1) < thr):
475
- # xred += thr
476
- #xred += 0.05
477
-
478
- sc_xred = xred@sc_matrix
479
- print(sc_xred)
480
- #np.all(sc_xred<1 and sc_xred>=0.0)
481
- # print(sc_xred<1)
482
- x = np.logical_and(sc_xred < 1+thr, sc_xred >= -thr)
483
- print(np.all(x, axis=1))
484
- selected = np.where(np.all(x, axis=1))[0]
485
- print(selected)
486
- symbols = atoms.get_chemical_symbols()
487
- psymbols = [symbols[i] for i in selected]
488
- patoms = Atoms(symbols=psymbols, positions=xcart[selected], cell=pcell)
489
- ncell = abs(np.linalg.det(sc_matrix))
490
- natom = len(atoms)
491
- if perfect:
492
- assert len(symbols) == int(
493
- natom/ncell), "The number of atoms in the found primitive cell does not equal to natom in the supercell divided by the size of the cell"
494
- return patoms, selected
495
-
496
-
497
- def test_find_primitive_cell():
498
- atoms = Atoms('HO', positions=[[0, 0, 0], [0, 0.2, 0]], cell=[1, 1, 1])
499
- sc_matrix = np.diag([1, 1, 3])
500
- atoms2 = make_supercell(atoms, sc_matrix)
501
- patoms = find_primitive_cell(atoms2, sc_matrix)
502
-
503
-
504
- def test():
505
- sc_mat = np.diag([1, 1, 3])
506
- #sc_mat[0, 1] = 2
507
- spm = SupercellMaker(sc_matrix=sc_mat, center=False)
508
- print("sc_vec", spm.sc_vec)
509
- print(spm.sc_cell([1, 1, 1]))
510
- print(spm.sc_pos([[0.5, 1, 1]]))
511
- print(spm.sc_pos([[0.5, 1, 0.5]]))
512
- print(spm.sc_trans_invariant(['Fe']))
513
- print(spm.sc_ijR({
514
- (0, 0, (0, 0, 1)): 1.2,
515
- (1, 1, (0, 0, 1)): 1.2,
516
- }, 2))
517
- print(spm.sc_index(indices=(1, 2)))
518
- print(spm.sc_index(indices=(1, 2), n_ind=4))
519
- from ase.atoms import Atoms
520
- atoms = Atoms('HO', positions=[[0, 0, 0], [0, 0.2, 0]], cell=[1, 1, 1])
521
- from ase.build import make_supercell
522
- atoms2 = make_supercell(atoms, sc_mat)
523
- atoms3 = spm.sc_atoms(atoms)
524
- # print(atoms2.get_positions())
525
- # print(atoms3.get_positions())
526
- assert (atoms2 == atoms3)
527
- assert (atoms2.get_positions() == atoms3.get_positions()).all()
528
-
529
-
530
- if __name__ == '__main__':
531
- # test()
532
- test_find_primitive_cell()
File without changes