TB2J 0.9.0.2__py3-none-any.whl → 0.9.0.4__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/Jdownfolder.py +2 -2
- TB2J/io_exchange/io_exchange.py +12 -0
- TB2J/io_merge.py +2 -1
- TB2J/lawaf/__init__.py +0 -0
- TB2J/lawaf/lawaf_interface.py +433 -0
- TB2J/manager.py +26 -3
- TB2J/symmetrize_J.py +121 -0
- {TB2J-0.9.0.2.dist-info → TB2J-0.9.0.4.dist-info}/METADATA +2 -1
- {TB2J-0.9.0.2.dist-info → TB2J-0.9.0.4.dist-info}/RECORD +23 -19
- {TB2J-0.9.0.2.dist-info → TB2J-0.9.0.4.dist-info}/WHEEL +1 -1
- TB2J-0.9.0.4.dist-info/entry_points.txt +2 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_downfold.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_eigen.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_magnon.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_magnon_dos.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_merge.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_rotate.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/TB2J_rotateDM.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/abacus2J.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/siesta2J.py +0 -0
- {TB2J-0.9.0.2.data → TB2J-0.9.0.4.data}/scripts/wann2J.py +0 -0
- {TB2J-0.9.0.2.dist-info → TB2J-0.9.0.4.dist-info}/LICENSE +0 -0
- {TB2J-0.9.0.2.dist-info → TB2J-0.9.0.4.dist-info}/top_level.txt +0 -0
TB2J/Jdownfolder.py
CHANGED
@@ -92,7 +92,7 @@ class PWFDownfolder:
|
|
92
92
|
# anchors={(0, 0, 0): (-1, -2, -3, -4)},
|
93
93
|
# anchors={(0, 0, 0): ()},
|
94
94
|
# use_proj=True,
|
95
|
-
enhance_Amn=2.0,
|
95
|
+
# enhance_Amn=2.0,
|
96
96
|
)
|
97
97
|
params.update(kwargs)
|
98
98
|
wann.set_parameters(**params)
|
@@ -134,7 +134,7 @@ class JDownfolder_pickle:
|
|
134
134
|
outpath,
|
135
135
|
qmesh=[7, 7, 7],
|
136
136
|
iso_only=False,
|
137
|
-
method="
|
137
|
+
method="lowdin",
|
138
138
|
**kwargs
|
139
139
|
):
|
140
140
|
self.exc = SpinIO.load_pickle(path=inpath, fname="TB2J.pickle")
|
TB2J/io_exchange/io_exchange.py
CHANGED
@@ -238,6 +238,18 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
238
238
|
def get_charge_iatom(self, iatom):
|
239
239
|
return self.charges[iatom]
|
240
240
|
|
241
|
+
def ijR_index_spin_to_atom(self, i, j, R):
|
242
|
+
return (self.iatom(i), self.iatom(j), R)
|
243
|
+
|
244
|
+
def ijR_index_atom_to_spin(self, iatom, jatom, R):
|
245
|
+
return (self.index_spin[iatom], self.index_spin[jatom], R)
|
246
|
+
|
247
|
+
def ijR_list(self):
|
248
|
+
return [(i, j, R) for R, i, j in self.exchange_Jdict]
|
249
|
+
|
250
|
+
def ijR_list_index_atom(self):
|
251
|
+
return [self.ijR_index_spin_to_atom(i, j, R) for R, i, j in self.exchange_Jdict]
|
252
|
+
|
241
253
|
def get_J(self, i, j, R, default=None):
|
242
254
|
i = self.i_spin(i)
|
243
255
|
j = self.i_spin(j)
|
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
|
-
|
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):
|
TB2J/lawaf/__init__.py
ADDED
File without changes
|
@@ -0,0 +1,433 @@
|
|
1
|
+
import os
|
2
|
+
from TB2J.myTB import MyTB, merge_tbmodels_spin
|
3
|
+
import numpy as np
|
4
|
+
from TB2J.exchange import ExchangeNCL
|
5
|
+
from TB2J.exchangeCL2 import ExchangeCL2
|
6
|
+
from TB2J.exchange_qspace import ExchangeCLQspace
|
7
|
+
from TB2J.utils import read_basis, auto_assign_basis_name
|
8
|
+
from ase.io import read
|
9
|
+
from TB2J.sisl_wrapper import SislWrapper
|
10
|
+
from TB2J.gpaw_wrapper import GPAWWrapper
|
11
|
+
from TB2J.wannier import parse_atoms
|
12
|
+
|
13
|
+
|
14
|
+
def gen_exchange(
|
15
|
+
path,
|
16
|
+
colinear=True,
|
17
|
+
groupby="spin",
|
18
|
+
posfile=None,
|
19
|
+
prefix_up="wannier90.up",
|
20
|
+
prefix_dn="wannier90.dn",
|
21
|
+
prefix_SOC="wannier90",
|
22
|
+
min_hopping_norm=1e-4,
|
23
|
+
max_distance=None,
|
24
|
+
efermi=0,
|
25
|
+
magnetic_elements=[],
|
26
|
+
kmesh=[4, 4, 4],
|
27
|
+
emin=-12.0,
|
28
|
+
emax=0.0,
|
29
|
+
nz=100,
|
30
|
+
exclude_orbs=[],
|
31
|
+
Rcut=None,
|
32
|
+
ne=None,
|
33
|
+
use_cache=False,
|
34
|
+
np=1,
|
35
|
+
output_path="TB2J_results",
|
36
|
+
wannier_type="wannier90",
|
37
|
+
qspace=False,
|
38
|
+
orb_decomposition=False,
|
39
|
+
write_density_matrix=False,
|
40
|
+
description="",
|
41
|
+
):
|
42
|
+
try:
|
43
|
+
fname = os.path.join(path, posfile)
|
44
|
+
print(f"Reading atomic structure from file {fname}.")
|
45
|
+
atoms = read(os.path.join(path, posfile))
|
46
|
+
except Exception:
|
47
|
+
print(
|
48
|
+
f"Cannot read atomic structure from file {fname}. Trying to read from Wannier input."
|
49
|
+
)
|
50
|
+
if colinear:
|
51
|
+
fname = os.path.join(path, f"{prefix_up}.win")
|
52
|
+
else:
|
53
|
+
fname = os.path.join(path, f"{prefix_SOC}.win")
|
54
|
+
|
55
|
+
print(f"Reading atomic structure from file {fname}.")
|
56
|
+
atoms = parse_atoms(fname)
|
57
|
+
|
58
|
+
basis_fname = os.path.join(path, "basis.txt")
|
59
|
+
if colinear:
|
60
|
+
if wannier_type.lower() == "wannier90":
|
61
|
+
print("Reading Wannier90 hamiltonian: spin up.")
|
62
|
+
tbmodel_up = MyTB.read_from_wannier_dir(
|
63
|
+
path=path, prefix=prefix_up, atoms=atoms, nls=False
|
64
|
+
)
|
65
|
+
print("Reading Wannier90 hamiltonian: spin down.")
|
66
|
+
tbmodel_dn = MyTB.read_from_wannier_dir(
|
67
|
+
path=path, prefix=prefix_dn, atoms=atoms, nls=False
|
68
|
+
)
|
69
|
+
if os.path.exists(basis_fname):
|
70
|
+
basis = read_basis(basis_fname)
|
71
|
+
else:
|
72
|
+
basis, _ = auto_assign_basis_name(
|
73
|
+
tbmodel_up.xred,
|
74
|
+
atoms,
|
75
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
76
|
+
)
|
77
|
+
elif wannier_type.lower() == "banddownfolder":
|
78
|
+
print("Reading Banddownfolder hamiltonian: spin up.")
|
79
|
+
tbmodel_up = MyTB.load_banddownfolder(
|
80
|
+
path=path, prefix=prefix_up, atoms=atoms, nls=False
|
81
|
+
)
|
82
|
+
print("Reading Banddownfolder hamiltonian: spin down.")
|
83
|
+
tbmodel_dn = MyTB.load_banddownfolder(
|
84
|
+
path=path, prefix=prefix_dn, atoms=atoms, nls=False
|
85
|
+
)
|
86
|
+
|
87
|
+
basis, _ = auto_assign_basis_name(
|
88
|
+
tbmodel_up.xred,
|
89
|
+
atoms,
|
90
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
91
|
+
)
|
92
|
+
else:
|
93
|
+
raise ValueError("wannier_type should be Wannier90 or banddownfolder.")
|
94
|
+
|
95
|
+
print("Starting to calculate exchange.")
|
96
|
+
description = f""" Input from collinear Wannier90 data.
|
97
|
+
Tight binding data from {path}.
|
98
|
+
Prefix of wannier function files:{prefix_up} and {prefix_dn}.
|
99
|
+
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
100
|
+
\n"""
|
101
|
+
if not qspace:
|
102
|
+
exchange = ExchangeCL2(
|
103
|
+
tbmodels=(tbmodel_up, tbmodel_dn),
|
104
|
+
atoms=atoms,
|
105
|
+
basis=basis,
|
106
|
+
efermi=efermi,
|
107
|
+
magnetic_elements=magnetic_elements,
|
108
|
+
kmesh=kmesh,
|
109
|
+
emin=emin,
|
110
|
+
emax=emax,
|
111
|
+
nz=nz,
|
112
|
+
exclude_orbs=exclude_orbs,
|
113
|
+
Rcut=Rcut,
|
114
|
+
ne=ne,
|
115
|
+
np=np,
|
116
|
+
use_cache=use_cache,
|
117
|
+
output_path=output_path,
|
118
|
+
write_density_matrix=write_density_matrix,
|
119
|
+
description=description,
|
120
|
+
)
|
121
|
+
else:
|
122
|
+
exchange = ExchangeCLQspace(
|
123
|
+
tbmodels=(tbmodel_up, tbmodel_dn),
|
124
|
+
atoms=atoms,
|
125
|
+
basis=basis,
|
126
|
+
efermi=efermi,
|
127
|
+
magnetic_elements=magnetic_elements,
|
128
|
+
kmesh=kmesh,
|
129
|
+
emin=emin,
|
130
|
+
emax=emax,
|
131
|
+
nz=nz,
|
132
|
+
exclude_orbs=exclude_orbs,
|
133
|
+
Rcut=Rcut,
|
134
|
+
ne=ne,
|
135
|
+
np=np,
|
136
|
+
use_cache=use_cache,
|
137
|
+
output_path=output_path,
|
138
|
+
write_density_matrix=write_density_matrix,
|
139
|
+
description=description,
|
140
|
+
)
|
141
|
+
|
142
|
+
exchange.run(path=output_path)
|
143
|
+
print("All calculation finsihed. The results are in TB2J_results directory.")
|
144
|
+
|
145
|
+
elif colinear and wannier_type.lower() == "banddownfolder":
|
146
|
+
print("Reading Wannier90 hamiltonian: spin up.")
|
147
|
+
tbmodel_up = MyTB.read_from_wannier_dir(
|
148
|
+
path=path, prefix=prefix_up, atoms=atoms, groupby=None, nls=False
|
149
|
+
)
|
150
|
+
print("Reading Wannier90 hamiltonian: spin down.")
|
151
|
+
tbmodel_dn = MyTB.read_from_wannier_dir(
|
152
|
+
path=path, prefix=prefix_dn, atoms=atoms, groupby=None, nls=False
|
153
|
+
)
|
154
|
+
tbmodel = merge_tbmodels_spin(tbmodel_up, tbmodel_dn)
|
155
|
+
basis, _ = auto_assign_basis_name(
|
156
|
+
tbmodel.xred,
|
157
|
+
atoms,
|
158
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
159
|
+
)
|
160
|
+
description = f""" Input from collinear BandDownfolder data.
|
161
|
+
Tight binding data from {path}.
|
162
|
+
Prefix of wannier function files:{prefix_up} and {prefix_dn}.
|
163
|
+
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
164
|
+
\n"""
|
165
|
+
print("Starting to calculate exchange.")
|
166
|
+
exchange = ExchangeCL2(
|
167
|
+
tbmodels=tbmodel,
|
168
|
+
atoms=atoms,
|
169
|
+
basis=basis,
|
170
|
+
efermi=efermi,
|
171
|
+
magnetic_elements=magnetic_elements,
|
172
|
+
kmesh=kmesh,
|
173
|
+
emin=emin,
|
174
|
+
emax=emax,
|
175
|
+
nz=nz,
|
176
|
+
exclude_orbs=exclude_orbs,
|
177
|
+
Rcut=Rcut,
|
178
|
+
ne=ne,
|
179
|
+
np=np,
|
180
|
+
use_cache=use_cache,
|
181
|
+
output_path=output_path,
|
182
|
+
write_density_matrix=write_density_matrix,
|
183
|
+
description=description,
|
184
|
+
)
|
185
|
+
exchange.run(path=output_path)
|
186
|
+
print("All calculation finsihed. The results are in TB2J_results directory.")
|
187
|
+
else:
|
188
|
+
print("Reading Wannier90 hamiltonian: non-colinear spin.")
|
189
|
+
groupby = groupby.lower().strip()
|
190
|
+
if groupby not in ["spin", "orbital"]:
|
191
|
+
raise ValueError("groupby can only be spin or orbital.")
|
192
|
+
tbmodel = MyTB.read_from_wannier_dir(
|
193
|
+
path=path, prefix=prefix_SOC, atoms=atoms, groupby=groupby, nls=True
|
194
|
+
)
|
195
|
+
if os.path.exists(basis_fname):
|
196
|
+
print("The use of basis file is deprecated. It will be ignored.")
|
197
|
+
# basis = read_basis(basis_fname)
|
198
|
+
else:
|
199
|
+
basis, _ = auto_assign_basis_name(
|
200
|
+
tbmodel.xred,
|
201
|
+
atoms,
|
202
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
203
|
+
)
|
204
|
+
description = f""" Input from non-collinear Wannier90 data.
|
205
|
+
Tight binding data from {path}.
|
206
|
+
Prefix of wannier function files:{prefix_SOC}.
|
207
|
+
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
208
|
+
The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
|
209
|
+
e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
|
210
|
+
If you need these component, try to do three calculations with spin along x, y, z, or use structure with z rotated to x, y and z. And then use TB2J_merge.py to get the full set of parameters.
|
211
|
+
|
212
|
+
\n"""
|
213
|
+
print("Starting to calculate exchange.")
|
214
|
+
exchange = ExchangeNCL(
|
215
|
+
tbmodels=tbmodel,
|
216
|
+
atoms=atoms,
|
217
|
+
basis=basis,
|
218
|
+
efermi=efermi,
|
219
|
+
magnetic_elements=magnetic_elements,
|
220
|
+
kmesh=kmesh,
|
221
|
+
emin=emin,
|
222
|
+
emax=emax,
|
223
|
+
nz=nz,
|
224
|
+
exclude_orbs=exclude_orbs,
|
225
|
+
Rcut=Rcut,
|
226
|
+
ne=ne,
|
227
|
+
np=np,
|
228
|
+
use_cache=use_cache,
|
229
|
+
description=description,
|
230
|
+
output_path=output_path,
|
231
|
+
write_density_matrix=write_density_matrix,
|
232
|
+
orb_decomposition=orb_decomposition,
|
233
|
+
)
|
234
|
+
print("\n")
|
235
|
+
exchange.run(path=output_path)
|
236
|
+
print(f"All calculation finsihed. The results are in {output_path} directory.")
|
237
|
+
|
238
|
+
|
239
|
+
def gen_exchange_siesta(
|
240
|
+
fdf_fname,
|
241
|
+
magnetic_elements=[],
|
242
|
+
include_orbs=None,
|
243
|
+
kmesh=[5, 5, 5],
|
244
|
+
emin=-12.0,
|
245
|
+
emax=0.0,
|
246
|
+
nz=100,
|
247
|
+
exclude_orbs=[],
|
248
|
+
Rcut=None,
|
249
|
+
ne=None,
|
250
|
+
np=1,
|
251
|
+
use_cache=False,
|
252
|
+
output_path="TB2J_results",
|
253
|
+
orb_decomposition=False,
|
254
|
+
description="",
|
255
|
+
):
|
256
|
+
try:
|
257
|
+
import sisl
|
258
|
+
except:
|
259
|
+
raise ImportError("sisl cannot be imported. Please install sisl first.")
|
260
|
+
|
261
|
+
from packaging import version
|
262
|
+
|
263
|
+
if version.parse(sisl.__version__) <= version.parse("0.10.0"):
|
264
|
+
raise ImportError(
|
265
|
+
f"sisl version is {sisl.__version__}, but should be larger than 0.10.0."
|
266
|
+
)
|
267
|
+
|
268
|
+
include_orbs = {}
|
269
|
+
if isinstance(magnetic_elements, str):
|
270
|
+
magnetic_elements = [magnetic_elements]
|
271
|
+
for element in magnetic_elements:
|
272
|
+
if "_" in element:
|
273
|
+
elem = element.split("_")[0]
|
274
|
+
orb = element.split("_")[1:]
|
275
|
+
include_orbs[elem] = orb
|
276
|
+
else:
|
277
|
+
include_orbs[element] = None
|
278
|
+
magnetic_elements = list(include_orbs.keys())
|
279
|
+
|
280
|
+
fdf = sisl.get_sile(fdf_fname)
|
281
|
+
# geom = fdf.read_geometry()
|
282
|
+
H = fdf.read_hamiltonian()
|
283
|
+
geom = H.geometry
|
284
|
+
if H.spin.is_colinear:
|
285
|
+
print("Reading Siesta hamiltonian: colinear spin.")
|
286
|
+
tbmodel_up = SislWrapper(H, spin=0, geom=geom)
|
287
|
+
tbmodel_dn = SislWrapper(H, spin=1, geom=geom)
|
288
|
+
basis = dict(zip(tbmodel_up.orbs, list(range(tbmodel_up.norb))))
|
289
|
+
print("Starting to calculate exchange.")
|
290
|
+
description = f""" Input from collinear Siesta data.
|
291
|
+
working directory: {os.getcwd()}
|
292
|
+
fdf_fname: {fdf_fname}.
|
293
|
+
\n"""
|
294
|
+
exchange = ExchangeCL2(
|
295
|
+
tbmodels=(tbmodel_up, tbmodel_dn),
|
296
|
+
atoms=tbmodel_up.atoms,
|
297
|
+
basis=basis,
|
298
|
+
efermi=0.0,
|
299
|
+
magnetic_elements=magnetic_elements,
|
300
|
+
include_orbs=include_orbs,
|
301
|
+
kmesh=kmesh,
|
302
|
+
emin=emin,
|
303
|
+
emax=emax,
|
304
|
+
nz=nz,
|
305
|
+
exclude_orbs=exclude_orbs,
|
306
|
+
Rcut=Rcut,
|
307
|
+
ne=ne,
|
308
|
+
np=np,
|
309
|
+
use_cache=use_cache,
|
310
|
+
output_path=output_path,
|
311
|
+
description=description,
|
312
|
+
)
|
313
|
+
exchange.run(path=output_path)
|
314
|
+
print("\n")
|
315
|
+
print(f"All calculation finsihed. The results are in {output_path} directory.")
|
316
|
+
|
317
|
+
elif H.spin.is_colinear and False:
|
318
|
+
print(
|
319
|
+
"Reading Siesta hamiltonian: colinear spin. Treat as non-colinear. For testing only."
|
320
|
+
)
|
321
|
+
tbmodel = SislWrapper(H, spin="merge", geom=geom)
|
322
|
+
basis = dict(zip(tbmodel.orbs, list(range(tbmodel.nbasis))))
|
323
|
+
print("Starting to calculate exchange.")
|
324
|
+
description = f""" Input from collinear Siesta data.
|
325
|
+
working directory: {os.getcwd()}
|
326
|
+
fdf_fname: {fdf_fname}.
|
327
|
+
\n"""
|
328
|
+
exchange = ExchangeNCL(
|
329
|
+
tbmodels=tbmodel,
|
330
|
+
atoms=tbmodel.atoms,
|
331
|
+
basis=basis,
|
332
|
+
efermi=0.0,
|
333
|
+
magnetic_elements=magnetic_elements,
|
334
|
+
include_orbs=include_orbs,
|
335
|
+
kmesh=kmesh,
|
336
|
+
emin=emin,
|
337
|
+
emax=emax,
|
338
|
+
nz=nz,
|
339
|
+
exclude_orbs=exclude_orbs,
|
340
|
+
Rcut=Rcut,
|
341
|
+
ne=ne,
|
342
|
+
np=np,
|
343
|
+
use_cache=use_cache,
|
344
|
+
description=description,
|
345
|
+
output_path=output_path,
|
346
|
+
orb_decomposition=orb_decomposition,
|
347
|
+
)
|
348
|
+
exchange.run(path=output_path)
|
349
|
+
print("\n")
|
350
|
+
print(f"All calculation finsihed. The results are in {output_path} directory.")
|
351
|
+
|
352
|
+
elif H.spin.is_spinorbit or H.spin.is_noncolinear:
|
353
|
+
print("Reading Siesta hamiltonian: non-colinear spin.")
|
354
|
+
tbmodel = SislWrapper(H, spin=None, geom=geom)
|
355
|
+
basis = dict(zip(tbmodel.orbs, list(range(tbmodel.nbasis))))
|
356
|
+
print("Starting to calculate exchange.")
|
357
|
+
description = f""" Input from non-collinear Siesta data.
|
358
|
+
working directory: {os.getcwd()}
|
359
|
+
fdf_fname: {fdf_fname}.
|
360
|
+
Warning: The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
|
361
|
+
e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
|
362
|
+
If you need these component, try to do three calculations with spin along x, y, z, or use structure with z rotated to x, y and z. And then use TB2J_merge.py to get the full set of parameters.
|
363
|
+
\n"""
|
364
|
+
exchange = ExchangeNCL(
|
365
|
+
tbmodels=tbmodel,
|
366
|
+
atoms=tbmodel.atoms,
|
367
|
+
basis=basis,
|
368
|
+
efermi=0.0,
|
369
|
+
magnetic_elements=magnetic_elements,
|
370
|
+
include_orbs=include_orbs,
|
371
|
+
kmesh=kmesh,
|
372
|
+
emin=emin,
|
373
|
+
emax=emax,
|
374
|
+
nz=nz,
|
375
|
+
exclude_orbs=exclude_orbs,
|
376
|
+
Rcut=Rcut,
|
377
|
+
ne=ne,
|
378
|
+
np=np,
|
379
|
+
use_cache=use_cache,
|
380
|
+
description=description,
|
381
|
+
output_path=output_path,
|
382
|
+
orb_decomposition=orb_decomposition,
|
383
|
+
)
|
384
|
+
exchange.run(path=output_path)
|
385
|
+
print("\n")
|
386
|
+
print(f"All calculation finsihed. The results are in {output_path} directory.")
|
387
|
+
|
388
|
+
|
389
|
+
def gen_exchange_gpaw(
|
390
|
+
gpw_fname,
|
391
|
+
magnetic_elements=[],
|
392
|
+
kmesh=[3, 3, 3],
|
393
|
+
emin=-12.0,
|
394
|
+
emax=0.0,
|
395
|
+
nz=50,
|
396
|
+
exclude_orbs=[],
|
397
|
+
Rcut=None,
|
398
|
+
use_cache=False,
|
399
|
+
output_path="TB2J_results",
|
400
|
+
description="",
|
401
|
+
):
|
402
|
+
print("Reading from GPAW data and calculate electronic structure.")
|
403
|
+
model = GPAWWrapper(gpw_fname=gpw_fname)
|
404
|
+
efermi = model.calc.get_fermi_level()
|
405
|
+
print(f"Fermi Energy: {efermi}")
|
406
|
+
poses = np.vstack([model.positions, model.positions])
|
407
|
+
basis, _ = auto_assign_basis_name(
|
408
|
+
poses,
|
409
|
+
model.atoms,
|
410
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
411
|
+
)
|
412
|
+
|
413
|
+
if model.calc.get_spin_polarized():
|
414
|
+
print("Starting to calculate exchange.")
|
415
|
+
exchange = ExchangeNCL(
|
416
|
+
tbmodels=model,
|
417
|
+
atoms=model.atoms,
|
418
|
+
efermi=efermi,
|
419
|
+
basis=basis,
|
420
|
+
magnetic_elements=magnetic_elements,
|
421
|
+
kmesh=kmesh,
|
422
|
+
emin=emin,
|
423
|
+
emax=emax,
|
424
|
+
nz=nz,
|
425
|
+
exclude_orbs=exclude_orbs,
|
426
|
+
Rcut=Rcut,
|
427
|
+
use_cache=use_cache,
|
428
|
+
output_path=output_path,
|
429
|
+
description=description,
|
430
|
+
)
|
431
|
+
exchange.run(path=output_path)
|
432
|
+
print("\n")
|
433
|
+
print(f"All calculation finsihed. The results are in {output_path} directory.")
|
TB2J/manager.py
CHANGED
@@ -9,6 +9,29 @@ from ase.io import read
|
|
9
9
|
from TB2J.sisl_wrapper import SislWrapper
|
10
10
|
from TB2J.gpaw_wrapper import GPAWWrapper
|
11
11
|
from TB2J.wannier import parse_atoms
|
12
|
+
from dataclasses import dataclass
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass
|
16
|
+
class TB2JParams:
|
17
|
+
colinear: bool = True
|
18
|
+
efermi: float = 0
|
19
|
+
magnetic_elements = []
|
20
|
+
kmesh = [4, 4, 4]
|
21
|
+
emin: float = -12.0
|
22
|
+
emax: float = 0.0
|
23
|
+
nz: int = 100
|
24
|
+
exclude_orbs = []
|
25
|
+
Rcut: float = None
|
26
|
+
ne: int = None
|
27
|
+
use_cache: bool = False
|
28
|
+
np: int = 1
|
29
|
+
output_path: str = "TB2J_results"
|
30
|
+
wannier_type: str = "wannier90"
|
31
|
+
qspace: bool = False
|
32
|
+
orb_decomposition: bool = False
|
33
|
+
write_density_matrix: bool = False
|
34
|
+
description: str = ""
|
12
35
|
|
13
36
|
|
14
37
|
def gen_exchange(
|
@@ -94,7 +117,7 @@ def gen_exchange(
|
|
94
117
|
|
95
118
|
print("Starting to calculate exchange.")
|
96
119
|
description = f""" Input from collinear Wannier90 data.
|
97
|
-
Tight binding data from {path}.
|
120
|
+
Tight binding data from {path}.
|
98
121
|
Prefix of wannier function files:{prefix_up} and {prefix_dn}.
|
99
122
|
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
100
123
|
\n"""
|
@@ -158,7 +181,7 @@ Warning: Please check if the noise level of Wannier function Hamiltonian to make
|
|
158
181
|
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
159
182
|
)
|
160
183
|
description = f""" Input from collinear BandDownfolder data.
|
161
|
-
Tight binding data from {path}.
|
184
|
+
Tight binding data from {path}.
|
162
185
|
Prefix of wannier function files:{prefix_up} and {prefix_dn}.
|
163
186
|
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
164
187
|
\n"""
|
@@ -202,7 +225,7 @@ Warning: Please check if the noise level of Wannier function Hamiltonian to make
|
|
202
225
|
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
203
226
|
)
|
204
227
|
description = f""" Input from non-collinear Wannier90 data.
|
205
|
-
Tight binding data from {path}.
|
228
|
+
Tight binding data from {path}.
|
206
229
|
Prefix of wannier function files:{prefix_SOC}.
|
207
230
|
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
208
231
|
The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
|
TB2J/symmetrize_J.py
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
from sympair import SymmetryPairFinder, SymmetryPairGroupDict
|
2
|
+
import numpy as np
|
3
|
+
from pathlib import Path
|
4
|
+
from TB2J.versioninfo import print_license
|
5
|
+
from TB2J.io_exchange import SpinIO
|
6
|
+
import copy
|
7
|
+
|
8
|
+
|
9
|
+
class TB2JSymmetrizer:
|
10
|
+
def __init__(self, exc, symprec=1e-8, verbose=True):
|
11
|
+
# list of pairs with the index of atoms
|
12
|
+
ijRs = exc.ijR_list_index_atom()
|
13
|
+
finder = SymmetryPairFinder(atoms=exc.atoms, pairs=ijRs, symprec=symprec)
|
14
|
+
self.verbose = verbose
|
15
|
+
|
16
|
+
if verbose:
|
17
|
+
print("=" * 30)
|
18
|
+
print_license()
|
19
|
+
print("-" * 30)
|
20
|
+
print(
|
21
|
+
"WARNING: The symmetry detection is based on the crystal symmetry, not the magnetic symmetry. Make sure if this is what you want."
|
22
|
+
)
|
23
|
+
print("-" * 30)
|
24
|
+
if exc.has_dmi:
|
25
|
+
print(
|
26
|
+
"WARNING: Currently only the isotropic exchange is symmetrized. Symmetrization of DMI and anisotropic exchange are not yet implemented."
|
27
|
+
)
|
28
|
+
|
29
|
+
print(f"Finding crystal symmetry with symprec of {symprec} Angstrom.")
|
30
|
+
print("Symmetry found:")
|
31
|
+
print(finder.spacegroup)
|
32
|
+
print(f"-" * 30)
|
33
|
+
self.pgdict = finder.get_symmetry_pair_group_dict()
|
34
|
+
self.exc = exc
|
35
|
+
self.new_exc = copy.deepcopy(exc)
|
36
|
+
|
37
|
+
def print_license(self):
|
38
|
+
print_license()
|
39
|
+
|
40
|
+
def symmetrize_J(self):
|
41
|
+
"""
|
42
|
+
Symmetrize the exchange parameters J.
|
43
|
+
"""
|
44
|
+
symJdict = {}
|
45
|
+
Jdict = self.exc.exchange_Jdict
|
46
|
+
ngroup = self.pgdict
|
47
|
+
for pairgroup in self.pgdict.groups:
|
48
|
+
ijRs = pairgroup.get_all_ijR()
|
49
|
+
ijRs_spin = [self.exc.ijR_index_atom_to_spin(*ijR) for ijR in ijRs]
|
50
|
+
Js = [self.exc.get_J(*ijR_spin) for ijR_spin in ijRs_spin]
|
51
|
+
Javg = np.average(Js)
|
52
|
+
for i, j, R in ijRs_spin:
|
53
|
+
symJdict[(R, i, j)] = Javg
|
54
|
+
self.new_exc.exchange_Jdict = symJdict
|
55
|
+
|
56
|
+
def output(self, path="TB2J_symmetrized"):
|
57
|
+
if path is None:
|
58
|
+
path = Path(".")
|
59
|
+
self.new_exc.write_all(path=path)
|
60
|
+
|
61
|
+
def run(self, path=None):
|
62
|
+
print("** Symmetrizing exchange parameters.")
|
63
|
+
self.symmetrize_J()
|
64
|
+
print("** Outputing the symmetrized exchange parameters.")
|
65
|
+
print(f"** Output path: {path} .")
|
66
|
+
self.output(path=path)
|
67
|
+
print("** Finished.")
|
68
|
+
|
69
|
+
|
70
|
+
def symmetrize_J(
|
71
|
+
exc=None,
|
72
|
+
path=None,
|
73
|
+
fname="TB2J.pickle",
|
74
|
+
symprec=1e-5,
|
75
|
+
output_path="TB2J_symmetrized",
|
76
|
+
):
|
77
|
+
"""
|
78
|
+
symmetrize the exchange parameters
|
79
|
+
parameters:
|
80
|
+
exc: exchange
|
81
|
+
"""
|
82
|
+
if exc is None:
|
83
|
+
exc = SpinIO.load_pickle(path=path, fname=fname)
|
84
|
+
symmetrizer = TB2JSymmetrizer(exc, symprec=symprec)
|
85
|
+
symmetrizer.run(path=output_path)
|
86
|
+
|
87
|
+
|
88
|
+
def symmetrize_J_cli():
|
89
|
+
from argparse import ArgumentParser
|
90
|
+
|
91
|
+
parser = ArgumentParser(
|
92
|
+
description="Symmetrize exchange parameters. Currently, it take the crystal symmetry into account and not the magnetic moment into account."
|
93
|
+
)
|
94
|
+
parser.add_argument(
|
95
|
+
"-i",
|
96
|
+
"--inpath",
|
97
|
+
default=None,
|
98
|
+
help="input path to the exchange parameters",
|
99
|
+
)
|
100
|
+
parser.add_argument(
|
101
|
+
"-o",
|
102
|
+
"--outpath",
|
103
|
+
default="TB2J_results_symmetrized",
|
104
|
+
help="output path to the symmetrized exchange parameters",
|
105
|
+
)
|
106
|
+
parser.add_argument(
|
107
|
+
"-s",
|
108
|
+
"--symprec",
|
109
|
+
type=float,
|
110
|
+
default=1e-5,
|
111
|
+
help="precision for symmetry detection. default is 1e-5 Angstrom",
|
112
|
+
)
|
113
|
+
args = parser.parse_args()
|
114
|
+
if args.inpath is None:
|
115
|
+
parser.print_help()
|
116
|
+
raise ValueError("Please provide the input path to the exchange.")
|
117
|
+
symmetrize_J(path=args.inpath, output_path=args.outpath, symprec=args.symprec)
|
118
|
+
|
119
|
+
|
120
|
+
if __name__ == "__main__":
|
121
|
+
symmetrize_J_cli()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: TB2J
|
3
|
-
Version: 0.9.0.
|
3
|
+
Version: 0.9.0.4
|
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
|
@@ -22,5 +22,6 @@ Requires-Dist: tqdm
|
|
22
22
|
Requires-Dist: pathos
|
23
23
|
Requires-Dist: packaging >=20.0
|
24
24
|
Requires-Dist: pre-commit
|
25
|
+
Requires-Dist: sympair >0.1.0
|
25
26
|
|
26
27
|
TB2J is a Python package aimed to compute automatically the magnetic interactions (superexchange and Dzyaloshinskii-Moriya) between atoms of magnetic crystals from DFT Hamiltonian based on Wannier functions or Linear combination of atomic orbitals. It uses the Green's function method and take the local rigid spin rotation as a perturbation. The package can take the output from Wannier90, which is interfaced with many density functional theory codes or from codes based on localised orbitals. A minimal user input is needed, which allows for an easily integration into a high-throughput workflows.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
TB2J/Jdownfolder.py,sha256=
|
1
|
+
TB2J/Jdownfolder.py,sha256=Mr6L9OncoAAL8oHehjMf6unp7a1Pv78smQOw6c_8nAc,9600
|
2
2
|
TB2J/Jtensor.py,sha256=t6OsqrSlYW6Im4H7ykVAW8Al_pFXN4C5yj2UEsV6r7g,3181
|
3
3
|
TB2J/MAE.py,sha256=-KWqxjKJvPFuxsMjm0c3nESyUFDeFTqsV7QzPJN-Fxo,7579
|
4
4
|
TB2J/Oiju.py,sha256=cNGv8N5uH_swGq7cnAt2OyiDfqtjLlLrwseGu0E4iaM,3383
|
@@ -17,9 +17,9 @@ TB2J/exchange_qspace.py,sha256=ZL68qBGFUaQ9BsSPsJaaoWOr9RssPiqX34R_9I3nk_8,8436
|
|
17
17
|
TB2J/gpaw_wrapper.py,sha256=aJ--9Dtyq7jOP1Hkh-Sh1nWcfXm6zKcljOCO0DNCAr0,6890
|
18
18
|
TB2J/green.py,sha256=QAJbDaR91QLres5gUPk37iqVsuQdPTt92VtEYLCl240,13170
|
19
19
|
TB2J/greentest.py,sha256=2ISSfhor9ecSEOi_E6b4Cv26wEIQlwlzca0ru8z44_E,1603
|
20
|
-
TB2J/io_merge.py,sha256=
|
20
|
+
TB2J/io_merge.py,sha256=E1_GfAB2HGpW-ipaO2lqU9SvaslwkiLxssn4DqJpMT8,6899
|
21
21
|
TB2J/kpoints.py,sha256=6XK2KqTncidEq3o9GuO6VEZRPNTRtWeXg9QfcV-9smI,532
|
22
|
-
TB2J/manager.py,sha256=
|
22
|
+
TB2J/manager.py,sha256=UQOFNsfFDAeQXbU4pWJWhnFfU6m11hxslPjn_JN_V14,15903
|
23
23
|
TB2J/mathutils.py,sha256=tHA6q3KPDpXLIbZHdDZ2NU5s886VVM_oEG490zQ6Ris,300
|
24
24
|
TB2J/myTB.py,sha256=ok_B4my29bOIghMSZfx0Es6G8FaXaIiLP4gPxTdSj00,17659
|
25
25
|
TB2J/orbmap.py,sha256=RCMJkOPGbfPrcZzcc5ia1ZMKBQWxGcyj8W1ve8BJaEw,6669
|
@@ -31,6 +31,7 @@ TB2J/rotate_atoms.py,sha256=Dwptn-wdDW4zYzjYb95yxTzuZOe9WPuLjh3d3-YcSs0,3277
|
|
31
31
|
TB2J/rotate_siestaDM.py,sha256=eR97rspdrRaK9YTwQwUKfobI0S9UnEcbEZ2f5IgR7Tk,1070
|
32
32
|
TB2J/sisl_wrapper.py,sha256=A5x1-tt8efUSPeGY5wM5m6-pJYQFXTCzQHVqD6RBa2g,14792
|
33
33
|
TB2J/supercell.py,sha256=4hgLGPBLRUDhtD-eF29v46ex7fHdkH-OENjS2wGLFww,19588
|
34
|
+
TB2J/symmetrize_J.py,sha256=4kNafz5VOg7SbqSHIkJ9g5Bo5c1Od6QdFJ_lkmEQGjw,3846
|
34
35
|
TB2J/tensor_rotate.py,sha256=4-DfT_Mg5e40fbd74M5W0D5DqmUq-kVOOLDkkkI834A,8083
|
35
36
|
TB2J/utest.py,sha256=z_ahi7tpHQF9WlHNQihcQ7qzfezRJQXQt28eB1X_z64,3897
|
36
37
|
TB2J/utils.py,sha256=DHkc7BK0KUGesfoAv1OxMgIw_iZzcFXh--3ybsFSd_c,12535
|
@@ -49,13 +50,15 @@ TB2J/abacus/test_read_stru.py,sha256=CpK4zWhlCVAMCmYQmp9Hy-A40OblZQLFpo5JokpNcWQ
|
|
49
50
|
TB2J/external/__init__.py,sha256=yD_ZIMi76H49rj6GAQpiB7UlKa3TgSaMkkLHT6M-8w8,137
|
50
51
|
TB2J/external/p_tqdm.py,sha256=ug1jy3-43r8iW7bC37xzPSIe0EjYKH_GUluGzMiQiDw,5831
|
51
52
|
TB2J/io_exchange/__init__.py,sha256=KfGHum7B8E4G_KKfillqw0lErtoyKEuFUUttHLs-mg4,32
|
52
|
-
TB2J/io_exchange/io_exchange.py,sha256=
|
53
|
+
TB2J/io_exchange/io_exchange.py,sha256=OhwWD0NTmvp06TlTP7Q_sDHEWrWB_TxW1S70h3TStvw,19786
|
53
54
|
TB2J/io_exchange/io_multibinit.py,sha256=8PDmWxzGuv-GwJosj2ZTmiyNY_duFVWJ4ekCuSqGdd8,6739
|
54
55
|
TB2J/io_exchange/io_pickle.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
56
|
TB2J/io_exchange/io_tomsasd.py,sha256=NqkAC1Fl-CUnFA21eBzSy_S5F_oeQFJysw4UukQbN8o,4173
|
56
57
|
TB2J/io_exchange/io_txt.py,sha256=BMr1eSILlKpgtjvDx7uw2VMAkEKSvGEPNxpaT_zev0I,10547
|
57
58
|
TB2J/io_exchange/io_uppasd.py,sha256=bI4iPEgnK4TvCZNvb6x2xYXgjW7pEehCqmcizy2pqFU,3301
|
58
59
|
TB2J/io_exchange/io_vampire.py,sha256=UllC4twf06_q2vBCnAYFzEDGvS8mSefwQXDquBuyc0M,5583
|
60
|
+
TB2J/lawaf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
|
+
TB2J/lawaf/lawaf_interface.py,sha256=4-4x9jJRHpUEqJuhc5HqpXfh2-Ze5G9Wg8gOtn-AqR4,15372
|
59
62
|
TB2J/mathutils/__init__.py,sha256=tQLBfHkZqdVfVxPOahy42qMUkFYnFFFhM-uc4QsYFxI,27
|
60
63
|
TB2J/mathutils/fermi.py,sha256=tzEicVoxE_5DxPDDZMvi4ynR1_Iqf-Qh0-0zfm-iVBo,480
|
61
64
|
TB2J/mathutils/kR_convert.py,sha256=p_9XWJVNanTzTK2rI6KRjTkbSq42la6N448-zJOsMwY,2671
|
@@ -76,18 +79,19 @@ TB2J/spinham/supercell.py,sha256=y17uUC6r3gQb278FhxIW4CABihfLTvKFj6flyXrCPR8,122
|
|
76
79
|
TB2J/wannier/__init__.py,sha256=7ojCbM84PYv1X1Tbo4NHI-d3gWmQsZB_xiYqbfxVV1E,80
|
77
80
|
TB2J/wannier/w90_parser.py,sha256=dbd63LuKyv2DVUzqRINGsbDzEsOxsQyE8_Ear_LQIRg,4620
|
78
81
|
TB2J/wannier/w90_tb_parser.py,sha256=qt8pnuprmPp9iIAYwPkPbmEzk6ZPgMq2xognoQp7vwc,4610
|
79
|
-
TB2J-0.9.0.
|
80
|
-
TB2J-0.9.0.
|
81
|
-
TB2J-0.9.0.
|
82
|
-
TB2J-0.9.0.
|
83
|
-
TB2J-0.9.0.
|
84
|
-
TB2J-0.9.0.
|
85
|
-
TB2J-0.9.0.
|
86
|
-
TB2J-0.9.0.
|
87
|
-
TB2J-0.9.0.
|
88
|
-
TB2J-0.9.0.
|
89
|
-
TB2J-0.9.0.
|
90
|
-
TB2J-0.9.0.
|
91
|
-
TB2J-0.9.0.
|
92
|
-
TB2J-0.9.0.
|
93
|
-
TB2J-0.9.0.
|
82
|
+
TB2J-0.9.0.4.data/scripts/TB2J_downfold.py,sha256=i4BVqnpDdgrX_amookVWeLGefGBn-qeAutWiwuY9SfQ,2099
|
83
|
+
TB2J-0.9.0.4.data/scripts/TB2J_eigen.py,sha256=Qs9v2hnMm2Tpfoa4h53muUKty2dZjwx8948MBoQooNg,1128
|
84
|
+
TB2J-0.9.0.4.data/scripts/TB2J_magnon.py,sha256=q7UwAmorRcFNk4tfE7gl_ny05l6p7pbD9Wm_LkIpKEw,3101
|
85
|
+
TB2J-0.9.0.4.data/scripts/TB2J_magnon_dos.py,sha256=TMXQvD2dIbO5FZ4tUMmxJgCgH2O2hDAPUNfEKO4z-x4,110
|
86
|
+
TB2J-0.9.0.4.data/scripts/TB2J_merge.py,sha256=y834SF4rIRn1L1ptkhczvavQpC-8Px6DTmDOOSaq_DE,1854
|
87
|
+
TB2J-0.9.0.4.data/scripts/TB2J_rotate.py,sha256=zgiDFuYZNmzKK0rwDmTaYD2OpRlmKA_VGeBx83w2Xwc,873
|
88
|
+
TB2J-0.9.0.4.data/scripts/TB2J_rotateDM.py,sha256=kCvF7gotuqAX1VnJ06cwfVm7RrhrdtiV5v7d9P2Pn_E,567
|
89
|
+
TB2J-0.9.0.4.data/scripts/abacus2J.py,sha256=M4B07lvTCDczTPTqvnDh_PERzCARAd09TLKv4aIdSQM,4408
|
90
|
+
TB2J-0.9.0.4.data/scripts/siesta2J.py,sha256=hBzS7ZgoHM3oXlTCQd-xVA07Ks2FiIwyRpQWUFITRPE,4303
|
91
|
+
TB2J-0.9.0.4.data/scripts/wann2J.py,sha256=2t2hWwyELskYCwkGDziCgiIAnfr6odLLJ6cQBJ2RQwQ,5714
|
92
|
+
TB2J-0.9.0.4.dist-info/LICENSE,sha256=CbZI-jyRTjiqIcWa244cRSHJdjjtUNqGR4HeJkgEwJw,1332
|
93
|
+
TB2J-0.9.0.4.dist-info/METADATA,sha256=N4p9P0wk_sV5xcSXikUnARnpDGs7FzEuXmQZ3pteyv4,1450
|
94
|
+
TB2J-0.9.0.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
95
|
+
TB2J-0.9.0.4.dist-info/entry_points.txt,sha256=RSoZk48jLcnVLGipFtQ3sFs9S7gbaMbX8VzVWomHjcg,74
|
96
|
+
TB2J-0.9.0.4.dist-info/top_level.txt,sha256=whYa5ByLYhl5XnTPBHSWr-IGD6VWmr5Ql2bye2qwV_s,5
|
97
|
+
TB2J-0.9.0.4.dist-info/RECORD,,
|
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
|