TB2Jflows 0.2__py3-none-any.whl → 0.2.0__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.
- TB2Jflows/__init__.py +5 -2
- TB2Jflows/ase_siesta.py +21 -22
- TB2Jflows/auto_siesta_TB2J.py +0 -2
- TB2Jflows/find_pp.py +91 -0
- TB2Jflows/mysiesta.py +570 -0
- TB2Jflows/siesta_basis.py +47 -0
- TB2Jflows/siesta_spinphonon.py +255 -0
- tb2jflows-0.2.0.dist-info/METADATA +77 -0
- tb2jflows-0.2.0.dist-info/RECORD +12 -0
- {tb2jflows-0.2.dist-info → tb2jflows-0.2.0.dist-info}/WHEEL +1 -2
- tb2jflows-0.2.dist-info/METADATA +0 -31
- tb2jflows-0.2.dist-info/RECORD +0 -9
- tb2jflows-0.2.dist-info/top_level.txt +0 -1
- {tb2jflows-0.2.dist-info → tb2jflows-0.2.0.dist-info}/licenses/LICENSE +0 -0
TB2Jflows/__init__.py
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
from TB2Jflows.ase_siesta import SiestaFlow
|
|
2
|
-
from TB2Jflows.auto_siesta_TB2J import auto_siesta_TB2J
|
|
1
|
+
from TB2Jflows.ase_siesta import SiestaFlow as SiestaFlow
|
|
2
|
+
from TB2Jflows.auto_siesta_TB2J import auto_siesta_TB2J as auto_siesta_TB2J
|
|
3
|
+
from TB2Jflows.siesta_spinphonon import (
|
|
4
|
+
compute_spinphonon_coupling as compute_spinphonon_coupling,
|
|
5
|
+
)
|
TB2Jflows/ase_siesta.py
CHANGED
|
@@ -5,11 +5,12 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
import ase
|
|
7
7
|
from ase.io.jsonio import decode, encode
|
|
8
|
-
from pyDFTutils.siesta import MySiesta
|
|
9
8
|
from TB2J.interfaces import gen_exchange_siesta
|
|
10
9
|
from TB2J.io_merge import merge
|
|
11
10
|
from TB2J.rotate_atoms import rotate_atom_spin, rotate_atom_xyz
|
|
12
11
|
|
|
12
|
+
from .mysiesta import MySiesta
|
|
13
|
+
|
|
13
14
|
|
|
14
15
|
class SiestaFlow:
|
|
15
16
|
def __init__(
|
|
@@ -24,7 +25,6 @@ class SiestaFlow:
|
|
|
24
25
|
restart=True,
|
|
25
26
|
metadata={},
|
|
26
27
|
fdf_arguments={},
|
|
27
|
-
relax_arguments={},
|
|
28
28
|
split_soc=False,
|
|
29
29
|
**kwargs,
|
|
30
30
|
):
|
|
@@ -33,6 +33,7 @@ class SiestaFlow:
|
|
|
33
33
|
self.xc = xc
|
|
34
34
|
self.kpts = kpts
|
|
35
35
|
self.Udict = Udict
|
|
36
|
+
|
|
36
37
|
# default fdf arguments
|
|
37
38
|
self.fdf_arguments = {
|
|
38
39
|
"MaxSCFIterations": 350,
|
|
@@ -51,7 +52,6 @@ class SiestaFlow:
|
|
|
51
52
|
self.root_path = root_path
|
|
52
53
|
self.restart = restart
|
|
53
54
|
self.kwargs = kwargs
|
|
54
|
-
self.relax_args = relax_arguments
|
|
55
55
|
|
|
56
56
|
# paths
|
|
57
57
|
self.metadata_path = os.path.join(self.root_path, "metadata.json")
|
|
@@ -160,7 +160,6 @@ class SiestaFlow:
|
|
|
160
160
|
MaxStressTol=0.1,
|
|
161
161
|
NumCGSteps=200,
|
|
162
162
|
):
|
|
163
|
-
print(f"Relaxation in {path}")
|
|
164
163
|
if (
|
|
165
164
|
self.restart
|
|
166
165
|
and self.metadata["already_relaxed"]
|
|
@@ -172,20 +171,20 @@ class SiestaFlow:
|
|
|
172
171
|
old_spin = self.spin
|
|
173
172
|
if use_collinear:
|
|
174
173
|
self.spin = "collinear"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
174
|
+
calc = self.get_calculator(atoms, path=self.relax_path, label=label)
|
|
175
|
+
calc.atoms = atoms
|
|
176
|
+
atoms = calc.relax(
|
|
177
|
+
atoms,
|
|
178
|
+
TypeOfRun=TypeOfRun,
|
|
179
|
+
VariableCell=VariableCell,
|
|
180
|
+
ConstantVolume=ConstantVolume,
|
|
181
|
+
RelaxCellOnly=RelaxCellOnly,
|
|
182
|
+
MaxForceTol=MaxForceTol,
|
|
183
|
+
MaxStressTol=MaxStressTol,
|
|
184
|
+
NumCGSteps=NumCGSteps,
|
|
185
|
+
)
|
|
186
|
+
self.spin = old_spin
|
|
187
|
+
self.relaxed_atoms = atoms
|
|
189
188
|
self.update_metadata(
|
|
190
189
|
{
|
|
191
190
|
"already_relaxed": True,
|
|
@@ -359,9 +358,9 @@ class SiestaFlow:
|
|
|
359
358
|
write_path=os.path.join(self.root_path, "TB2J_results_merged"),
|
|
360
359
|
)
|
|
361
360
|
|
|
362
|
-
def runall_collinear(self, atoms, relax=True, scf=True, TB2J=True,
|
|
361
|
+
def runall_collinear(self, atoms, relax=True, scf=True, TB2J=True, **kwargs):
|
|
363
362
|
if relax:
|
|
364
|
-
atoms = self.relax(atoms
|
|
363
|
+
atoms = self.relax(atoms)
|
|
365
364
|
if scf:
|
|
366
365
|
self.scf_calculation_collinear(atoms, label="siesta")
|
|
367
366
|
if TB2J:
|
|
@@ -371,7 +370,7 @@ class SiestaFlow:
|
|
|
371
370
|
self, atoms, relax=True, scf=True, TB2J=True, rotate_type="structure", **kwargs
|
|
372
371
|
):
|
|
373
372
|
if relax:
|
|
374
|
-
atoms = self.relax(atoms
|
|
373
|
+
atoms = self.relax(atoms)
|
|
375
374
|
if scf:
|
|
376
375
|
self.scf_calculation_with_rotations(
|
|
377
376
|
atoms, rotate_type=rotate_type, label="siesta"
|
|
@@ -382,7 +381,7 @@ class SiestaFlow:
|
|
|
382
381
|
|
|
383
382
|
def runall_split_soc(self, atoms, relax=True, scf=True, TB2J=True, **kwargs):
|
|
384
383
|
if relax:
|
|
385
|
-
atoms = self.relax(atoms
|
|
384
|
+
atoms = self.relax(atoms)
|
|
386
385
|
if scf:
|
|
387
386
|
self.scf_calculatoin_split_soc(atoms, label="siesta")
|
|
388
387
|
if TB2J:
|
TB2Jflows/auto_siesta_TB2J.py
CHANGED
|
@@ -52,7 +52,6 @@ def auto_siesta_TB2J(
|
|
|
52
52
|
TB2J=True,
|
|
53
53
|
rotate_type="structure",
|
|
54
54
|
fincore=True,
|
|
55
|
-
relax_kwargs={},
|
|
56
55
|
siesta_kwargs={},
|
|
57
56
|
TB2J_kwargs={},
|
|
58
57
|
fdf_kwargs={},
|
|
@@ -100,7 +99,6 @@ def auto_siesta_TB2J(
|
|
|
100
99
|
fincore=fincore,
|
|
101
100
|
Udict=Udict,
|
|
102
101
|
split_soc=split_soc,
|
|
103
|
-
relax_arguments = relax_kwargs,
|
|
104
102
|
**siesta_kwargs,
|
|
105
103
|
)
|
|
106
104
|
flow.write_metadata()
|
TB2Jflows/find_pp.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from ase.data import atomic_numbers
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PPFinder:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def get_pp_path(self, element, xc, label, rel):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DojoFinder:
|
|
15
|
+
def __init__(self, path=None):
|
|
16
|
+
if path is None:
|
|
17
|
+
self.path = os.environ["DOJO_PATH"]
|
|
18
|
+
else:
|
|
19
|
+
self.path = path
|
|
20
|
+
|
|
21
|
+
def get_pp_path(
|
|
22
|
+
self, xc: str, typ="NC", rel="sr", version="04", accuracy="standard", fmt="psml"
|
|
23
|
+
):
|
|
24
|
+
typ = typ.lower()
|
|
25
|
+
xc = xc.lower()
|
|
26
|
+
if xc == "lda":
|
|
27
|
+
xc = "pbe"
|
|
28
|
+
dirname = os.path.join(
|
|
29
|
+
self.path, f"{typ}-{rel}-{version}_{xc}_{accuracy}_{fmt}"
|
|
30
|
+
)
|
|
31
|
+
if not os.path.exists(dirname):
|
|
32
|
+
raise FileNotFoundError(f"File Not found: {dirname}")
|
|
33
|
+
return dirname
|
|
34
|
+
|
|
35
|
+
def get_pp_fname(
|
|
36
|
+
self,
|
|
37
|
+
element,
|
|
38
|
+
xc: str,
|
|
39
|
+
typ="NC",
|
|
40
|
+
rel="sr",
|
|
41
|
+
version="04",
|
|
42
|
+
accuracy="standard",
|
|
43
|
+
fincore=False,
|
|
44
|
+
fmt="psml",
|
|
45
|
+
):
|
|
46
|
+
if 57 < atomic_numbers[element] <= 70:
|
|
47
|
+
if fincore:
|
|
48
|
+
fname = os.path.join(
|
|
49
|
+
self.get_pp_path(
|
|
50
|
+
xc=xc,
|
|
51
|
+
typ=typ,
|
|
52
|
+
rel=rel,
|
|
53
|
+
version=version,
|
|
54
|
+
accuracy=accuracy,
|
|
55
|
+
fmt=fmt,
|
|
56
|
+
),
|
|
57
|
+
f"fincore/{element}.{fmt}",
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
fname = os.path.join(
|
|
61
|
+
self.get_pp_path(
|
|
62
|
+
xc=xc,
|
|
63
|
+
typ=typ,
|
|
64
|
+
rel=rel,
|
|
65
|
+
version=version,
|
|
66
|
+
accuracy=accuracy,
|
|
67
|
+
fmt=fmt,
|
|
68
|
+
),
|
|
69
|
+
f"withf/{element}.{fmt}",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
else:
|
|
73
|
+
fname = os.path.join(
|
|
74
|
+
self.get_pp_path(
|
|
75
|
+
xc=xc, typ=typ, rel=rel, version=version, accuracy=accuracy, fmt=fmt
|
|
76
|
+
),
|
|
77
|
+
f"{element}.{fmt}",
|
|
78
|
+
)
|
|
79
|
+
if not os.path.exists(fname):
|
|
80
|
+
raise FileNotFoundError(f"File Not found: {fname}")
|
|
81
|
+
return fname
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test():
|
|
85
|
+
finder = DojoFinder(path=os.path.expanduser("~/projects/pp/dojo"))
|
|
86
|
+
finder.get_pp_path(element="Sr", xc="pbesol")
|
|
87
|
+
finder.get_pp_path(element="Srg", xc="pbe")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
test()
|
TB2Jflows/mysiesta.py
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
from os.path import isfile, islink, join
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from ase import Atoms
|
|
8
|
+
from ase.calculators.siesta import Siesta
|
|
9
|
+
from ase.calculators.siesta.parameters import PAOBasisBlock, Species, format_fdf
|
|
10
|
+
from ase.data import atomic_numbers
|
|
11
|
+
from ase.io import write
|
|
12
|
+
from ase.units import Bohr
|
|
13
|
+
|
|
14
|
+
from .find_pp import DojoFinder
|
|
15
|
+
|
|
16
|
+
# from pyDFTutils.siesta.pdos import gen_pdos_figure, plot_layer_pdos
|
|
17
|
+
from .siesta_basis import fincore_basis, withf_basis
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_valence_charge(pseudopotential):
|
|
21
|
+
raise NotImplementedError(
|
|
22
|
+
"get_valence_charge is not available in the current environment."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def read_vca_synth_block(synth_block_filename, species_number):
|
|
27
|
+
raise NotImplementedError(
|
|
28
|
+
"read_vca_synth_block is not available in the current environment."
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
synthetic_atoms_dict_fincore = {
|
|
33
|
+
# Ce-Lu
|
|
34
|
+
"Ce": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
35
|
+
"Pr": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
36
|
+
"Nd": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
37
|
+
"Pm": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
38
|
+
"Sm": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
39
|
+
"Eu": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
40
|
+
"Gd": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
41
|
+
"Tb": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
42
|
+
"Dy": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
43
|
+
"Ho": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
44
|
+
"Er": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
45
|
+
"Tm": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
46
|
+
"Yb": ((6, 5, 5, 5), (2, 6, 1, 0)),
|
|
47
|
+
"Lu": ((5, 5, 5, 4), (2, 6, 3, 0)),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def read_siesta_xv(fd):
|
|
52
|
+
vectors = []
|
|
53
|
+
for i in range(3):
|
|
54
|
+
data = next(fd).split()
|
|
55
|
+
vectors.append([float(data[j]) * Bohr for j in range(3)])
|
|
56
|
+
|
|
57
|
+
# Read number of atoms (line 4)
|
|
58
|
+
natoms = int(next(fd).split()[0])
|
|
59
|
+
|
|
60
|
+
# Read remaining lines
|
|
61
|
+
speciesnumber, atomnumbers, xyz, V = [], [], [], []
|
|
62
|
+
for line in fd:
|
|
63
|
+
if len(line) > 5: # Ignore blank lines
|
|
64
|
+
data = line.split()
|
|
65
|
+
speciesnumber.append(int(data[0]))
|
|
66
|
+
atomnumbers.append(int(data[1]) % 200)
|
|
67
|
+
xyz.append([float(data[2 + j]) * Bohr for j in range(3)])
|
|
68
|
+
V.append([float(data[5 + j]) * Bohr for j in range(3)])
|
|
69
|
+
|
|
70
|
+
vectors = np.array(vectors)
|
|
71
|
+
atomnumbers = np.array(atomnumbers)
|
|
72
|
+
xyz = np.array(xyz)
|
|
73
|
+
atoms = Atoms(numbers=atomnumbers, positions=xyz, cell=vectors, pbc=True)
|
|
74
|
+
assert natoms == len(atoms)
|
|
75
|
+
return atoms
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def read_xv(fname):
|
|
79
|
+
with open(fname) as myfile:
|
|
80
|
+
atoms = read_siesta_xv(myfile)
|
|
81
|
+
return atoms
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_species(atoms, xc, rel="sr", accuracy="standard", fincore=False):
|
|
85
|
+
finder = DojoFinder()
|
|
86
|
+
elems = list(dict.fromkeys(atoms.get_chemical_symbols()).keys())
|
|
87
|
+
elem_dict = dict(zip(elems, range(1, len(elems) + 1)))
|
|
88
|
+
pseudo_path = finder.get_pp_path(xc=xc)
|
|
89
|
+
species = [
|
|
90
|
+
Species(
|
|
91
|
+
symbol=elem,
|
|
92
|
+
pseudopotential=finder.get_pp_fname(
|
|
93
|
+
elem, xc=xc, rel=rel, accuracy=accuracy, fincore=fincore
|
|
94
|
+
),
|
|
95
|
+
ghost=False,
|
|
96
|
+
)
|
|
97
|
+
for elem in elem_dict.keys()
|
|
98
|
+
]
|
|
99
|
+
return pseudo_path, species
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cart2sph(vec):
|
|
103
|
+
x, y, z = vec
|
|
104
|
+
r = np.linalg.norm(vec) # r
|
|
105
|
+
if r < 1e-10:
|
|
106
|
+
theta, phi = 0.0, 0.0
|
|
107
|
+
else:
|
|
108
|
+
# note that there are many conventions, here is the ISO convention.
|
|
109
|
+
phi = math.atan2(y, x) * 180 / math.pi # phi
|
|
110
|
+
theta = math.acos(z / r) * 180 / math.pi # theta
|
|
111
|
+
return r, theta, phi
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class MySiesta(Siesta):
|
|
115
|
+
def __init__(
|
|
116
|
+
self,
|
|
117
|
+
atoms=None,
|
|
118
|
+
command=None,
|
|
119
|
+
xc="LDA",
|
|
120
|
+
spin="non-polarized",
|
|
121
|
+
basis_set="DZP",
|
|
122
|
+
species=None,
|
|
123
|
+
ghosts=[],
|
|
124
|
+
synthetic_atoms={},
|
|
125
|
+
input_basis_set={},
|
|
126
|
+
pseudo_path=None,
|
|
127
|
+
input_pp={},
|
|
128
|
+
pp_accuracy="standard",
|
|
129
|
+
fincore=False,
|
|
130
|
+
**kwargs,
|
|
131
|
+
):
|
|
132
|
+
# non-perturnbative polarized orbital.
|
|
133
|
+
self.npt_elems = set()
|
|
134
|
+
|
|
135
|
+
if fincore:
|
|
136
|
+
self.synthetic_atoms = synthetic_atoms_dict_fincore.copy()
|
|
137
|
+
self.synthetic_atoms.update(synthetic_atoms)
|
|
138
|
+
else:
|
|
139
|
+
self.synthetic_atoms = synthetic_atoms
|
|
140
|
+
|
|
141
|
+
if fincore:
|
|
142
|
+
input_basis_set.update(fincore_basis)
|
|
143
|
+
else:
|
|
144
|
+
input_basis_set.update(withf_basis)
|
|
145
|
+
|
|
146
|
+
if atoms is not None:
|
|
147
|
+
finder = DojoFinder()
|
|
148
|
+
elems = list(dict.fromkeys(atoms.get_chemical_symbols()).keys())
|
|
149
|
+
self.elem_dict = dict(zip(elems, range(1, len(elems) + 1)))
|
|
150
|
+
symbols = atoms.get_chemical_symbols()
|
|
151
|
+
|
|
152
|
+
# ghosts
|
|
153
|
+
ghost_symbols = [symbols[i] for i in ghosts]
|
|
154
|
+
ghost_elems = list(dict.fromkeys(ghost_symbols).keys())
|
|
155
|
+
tags = [1 if i in ghosts else 0 for i in range(len(atoms))]
|
|
156
|
+
atoms.set_tags(tags)
|
|
157
|
+
|
|
158
|
+
if pseudo_path is None:
|
|
159
|
+
pseudo_path = finder.get_pp_path(xc=xc, accuracy=pp_accuracy)
|
|
160
|
+
|
|
161
|
+
if spin == "spin-orbit":
|
|
162
|
+
rel = "fr"
|
|
163
|
+
else:
|
|
164
|
+
rel = "sr"
|
|
165
|
+
species = []
|
|
166
|
+
for elem, index in self.elem_dict.items():
|
|
167
|
+
if elem not in input_basis_set:
|
|
168
|
+
bselem = basis_set
|
|
169
|
+
if elem in ["Li", "Be", "Na", "Mg", "Sm"]:
|
|
170
|
+
self.npt_elems.add(f"{elem}.{index}")
|
|
171
|
+
else:
|
|
172
|
+
bselem = PAOBasisBlock(input_basis_set[elem])
|
|
173
|
+
if elem not in input_pp:
|
|
174
|
+
pseudopotential = finder.get_pp_fname(
|
|
175
|
+
elem, xc=xc, rel=rel, accuracy=pp_accuracy, fincore=fincore
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
pseudopotential = os.path.join(pseudo_path, input_pp[elem])
|
|
179
|
+
|
|
180
|
+
if elem in self.synthetic_atoms:
|
|
181
|
+
excess_charge = 0
|
|
182
|
+
else:
|
|
183
|
+
excess_charge = None
|
|
184
|
+
|
|
185
|
+
species.append(
|
|
186
|
+
Species(
|
|
187
|
+
symbol=elem,
|
|
188
|
+
pseudopotential=pseudopotential,
|
|
189
|
+
basis_set=bselem,
|
|
190
|
+
ghost=False,
|
|
191
|
+
excess_charge=excess_charge,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
for elem in ghost_elems:
|
|
195
|
+
species.append(
|
|
196
|
+
Species(
|
|
197
|
+
symbol=elem,
|
|
198
|
+
pseudopotential=finder.get_pp_fname(
|
|
199
|
+
elem, xc=xc, rel=rel, accuracy=pp_accuracy, fincore=fincore
|
|
200
|
+
),
|
|
201
|
+
tag=1,
|
|
202
|
+
ghost=True,
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
Siesta.__init__(
|
|
207
|
+
self,
|
|
208
|
+
xc=xc,
|
|
209
|
+
spin=spin,
|
|
210
|
+
atoms=atoms,
|
|
211
|
+
pseudo_path=pseudo_path,
|
|
212
|
+
species=species,
|
|
213
|
+
**kwargs,
|
|
214
|
+
)
|
|
215
|
+
self.set_npt_elements()
|
|
216
|
+
self.set_synthetic_atoms()
|
|
217
|
+
|
|
218
|
+
def _write_species(self, fd, atoms):
|
|
219
|
+
"""Write input related the different species.
|
|
220
|
+
|
|
221
|
+
Parameters:
|
|
222
|
+
- f: An open file object.
|
|
223
|
+
- atoms: An atoms object.
|
|
224
|
+
"""
|
|
225
|
+
species, species_numbers = self.species(atoms)
|
|
226
|
+
|
|
227
|
+
if self["pseudo_path"] is not None:
|
|
228
|
+
pseudo_path = self["pseudo_path"]
|
|
229
|
+
elif "SIESTA_PP_PATH" in os.environ:
|
|
230
|
+
pseudo_path = os.environ["SIESTA_PP_PATH"]
|
|
231
|
+
else:
|
|
232
|
+
mess = "Please set the environment variable 'SIESTA_PP_PATH'"
|
|
233
|
+
raise Exception(mess)
|
|
234
|
+
|
|
235
|
+
fd.write(format_fdf("NumberOfSpecies", len(species)))
|
|
236
|
+
fd.write(format_fdf("NumberOfAtoms", len(atoms)))
|
|
237
|
+
|
|
238
|
+
pao_basis = []
|
|
239
|
+
chemical_labels = []
|
|
240
|
+
basis_sizes = []
|
|
241
|
+
synth_blocks = []
|
|
242
|
+
for species_number, spec in enumerate(species):
|
|
243
|
+
species_number += 1
|
|
244
|
+
symbol = spec["symbol"]
|
|
245
|
+
atomic_number = atomic_numbers[symbol]
|
|
246
|
+
|
|
247
|
+
if spec["pseudopotential"] is None:
|
|
248
|
+
if self.pseudo_qualifier() == "":
|
|
249
|
+
label = symbol
|
|
250
|
+
pseudopotential = label + ".psf"
|
|
251
|
+
else:
|
|
252
|
+
label = ".".join([symbol, self.pseudo_qualifier()])
|
|
253
|
+
pseudopotential = label + ".psf"
|
|
254
|
+
else:
|
|
255
|
+
pseudopotential = spec["pseudopotential"]
|
|
256
|
+
label = os.path.basename(pseudopotential)
|
|
257
|
+
label = ".".join(label.split(".")[:-1])
|
|
258
|
+
|
|
259
|
+
if not os.path.isabs(pseudopotential):
|
|
260
|
+
pseudopotential = join(pseudo_path, pseudopotential)
|
|
261
|
+
|
|
262
|
+
if not os.path.exists(pseudopotential):
|
|
263
|
+
mess = "Pseudopotential '%s' not found" % pseudopotential
|
|
264
|
+
raise RuntimeError(mess)
|
|
265
|
+
|
|
266
|
+
name = os.path.basename(pseudopotential)
|
|
267
|
+
name = name.split(".")
|
|
268
|
+
name.insert(-1, str(species_number))
|
|
269
|
+
if spec["ghost"]:
|
|
270
|
+
name.insert(-1, "ghost")
|
|
271
|
+
atomic_number = -atomic_number
|
|
272
|
+
|
|
273
|
+
name = ".".join(name)
|
|
274
|
+
pseudo_targetpath = self.getpath(name)
|
|
275
|
+
|
|
276
|
+
if join(os.getcwd(), name) != pseudopotential:
|
|
277
|
+
if islink(pseudo_targetpath) or isfile(pseudo_targetpath):
|
|
278
|
+
os.remove(pseudo_targetpath)
|
|
279
|
+
symlink_pseudos = self["symlink_pseudos"]
|
|
280
|
+
|
|
281
|
+
symlink_pseudos = False
|
|
282
|
+
|
|
283
|
+
if symlink_pseudos is None:
|
|
284
|
+
symlink_pseudos = not os.name == "nt"
|
|
285
|
+
|
|
286
|
+
if symlink_pseudos:
|
|
287
|
+
os.symlink(pseudopotential, pseudo_targetpath)
|
|
288
|
+
else:
|
|
289
|
+
shutil.copy(pseudopotential, pseudo_targetpath)
|
|
290
|
+
if spec["excess_charge"] is not None:
|
|
291
|
+
atomic_number += 200
|
|
292
|
+
# n_atoms = sum(np.array(species_numbers) == species_number)
|
|
293
|
+
|
|
294
|
+
# if spec["excess_charge"] != 0:
|
|
295
|
+
# paec = float(spec["excess_charge"]) / n_atoms
|
|
296
|
+
# vc = get_valence_charge(pseudopotential)
|
|
297
|
+
# fraction = float(vc + paec) / vc
|
|
298
|
+
# pseudo_head = name[:-4]
|
|
299
|
+
# fractional_command = os.environ["SIESTA_UTIL_FRACTIONAL"]
|
|
300
|
+
# cmd = "%s %s %.7f" % (fractional_command, pseudo_head, fraction)
|
|
301
|
+
# os.system(cmd)
|
|
302
|
+
#
|
|
303
|
+
# pseudo_head += "-Fraction-%.5f" % fraction
|
|
304
|
+
# synth_pseudo = pseudo_head + ".psf"
|
|
305
|
+
# synth_block_filename = pseudo_head + ".synth"
|
|
306
|
+
# os.remove(name)
|
|
307
|
+
# shutil.copyfile(synth_pseudo, name)
|
|
308
|
+
# synth_block = read_vca_synth_block(
|
|
309
|
+
# synth_block_filename, species_number=species_number
|
|
310
|
+
# )
|
|
311
|
+
# synth_blocks.append(synth_block)
|
|
312
|
+
# else:
|
|
313
|
+
# synth_block = self.synthetic_atoms[symbol]
|
|
314
|
+
if symbol in self.synthetic_atoms:
|
|
315
|
+
synth_block = self.synthetic_atoms[symbol]
|
|
316
|
+
synth_blocks.append(synth_block)
|
|
317
|
+
|
|
318
|
+
if len(synth_blocks) > 0:
|
|
319
|
+
fd.write(format_fdf("SyntheticAtoms", list(synth_blocks)))
|
|
320
|
+
|
|
321
|
+
label = ".".join(np.array(name.split("."))[:-1])
|
|
322
|
+
string = " %d %d %s" % (species_number, atomic_number, label)
|
|
323
|
+
chemical_labels.append(string)
|
|
324
|
+
if isinstance(spec["basis_set"], PAOBasisBlock):
|
|
325
|
+
pao_basis.append(spec["basis_set"].script(label))
|
|
326
|
+
else:
|
|
327
|
+
basis_sizes.append((" " + label, spec["basis_set"]))
|
|
328
|
+
fd.write((format_fdf("ChemicalSpecieslabel", chemical_labels)))
|
|
329
|
+
fd.write("\n")
|
|
330
|
+
fd.write((format_fdf("PAO.Basis", pao_basis)))
|
|
331
|
+
fd.write((format_fdf("PAO.BasisSizes", basis_sizes)))
|
|
332
|
+
fd.write("\n")
|
|
333
|
+
|
|
334
|
+
def set_npt_elements(self):
|
|
335
|
+
if len(self.npt_elems) > 0:
|
|
336
|
+
npt_text = []
|
|
337
|
+
for name in self.npt_elems:
|
|
338
|
+
npt_text.append(f"{name} non-perturbative ")
|
|
339
|
+
# npt_text += "%endblock PAO.PolarizationScheme\n"
|
|
340
|
+
self["fdf_arguments"].update({"PAO.PolarizationScheme": npt_text})
|
|
341
|
+
|
|
342
|
+
def set_synthetic_atoms(self):
|
|
343
|
+
print("setting syn")
|
|
344
|
+
nsyn = len(self.synthetic_atoms)
|
|
345
|
+
if nsyn > 0:
|
|
346
|
+
syntext = []
|
|
347
|
+
# syntext.append(f"{nsyn}")
|
|
348
|
+
for name, content in self.synthetic_atoms.items():
|
|
349
|
+
if name in self.elem_dict:
|
|
350
|
+
syntext.append(f"{self.elem_dict[name]}")
|
|
351
|
+
syntext.append(" ".join([str(x) for x in content[0]]))
|
|
352
|
+
syntext.append(" ".join([str(x) for x in content[1]]))
|
|
353
|
+
if len(syntext) > 0:
|
|
354
|
+
self["fdf_arguments"].update({"SyntheticAtoms": syntext})
|
|
355
|
+
|
|
356
|
+
# print("setting syn:", syntext)
|
|
357
|
+
|
|
358
|
+
def set_fdf_arguments(self, fdf_arguments):
|
|
359
|
+
self["fdf_arguments"].update(fdf_arguments)
|
|
360
|
+
|
|
361
|
+
def set_mixer(
|
|
362
|
+
self,
|
|
363
|
+
method="pulay",
|
|
364
|
+
weight=0.05,
|
|
365
|
+
history=10,
|
|
366
|
+
restart=25,
|
|
367
|
+
restart_save=4,
|
|
368
|
+
linear_after=0,
|
|
369
|
+
linear_after_weight=0.1,
|
|
370
|
+
):
|
|
371
|
+
pass
|
|
372
|
+
|
|
373
|
+
def update_fdf_arguments(self, fdf_arguments):
|
|
374
|
+
self["fdf_arguments"].update(fdf_arguments)
|
|
375
|
+
|
|
376
|
+
def add_Hubbard_U(
|
|
377
|
+
self,
|
|
378
|
+
specy,
|
|
379
|
+
n=3,
|
|
380
|
+
l=2, # noqa: E741
|
|
381
|
+
U=0,
|
|
382
|
+
J=0,
|
|
383
|
+
rc=0.0,
|
|
384
|
+
Fermi_cut=0.0,
|
|
385
|
+
scale_factor="0.95",
|
|
386
|
+
):
|
|
387
|
+
if "Udict" not in self.__dict__:
|
|
388
|
+
self.Udict = dict()
|
|
389
|
+
idx = self.elem_dict[specy]
|
|
390
|
+
specy_label = f"{specy}.{idx}"
|
|
391
|
+
self.Udict[specy_label] = {
|
|
392
|
+
"n": n,
|
|
393
|
+
"l": l,
|
|
394
|
+
"U": U,
|
|
395
|
+
"J": J,
|
|
396
|
+
"rc": rc,
|
|
397
|
+
"Fermi_cut": Fermi_cut,
|
|
398
|
+
"scale_factor": scale_factor,
|
|
399
|
+
}
|
|
400
|
+
self.set_Hubbard_U(self.Udict)
|
|
401
|
+
|
|
402
|
+
def set_Hubbard_U(self, Udict):
|
|
403
|
+
"""
|
|
404
|
+
Udict: {'Fe': {'n':n, 'l':l, 'U':U, 'J', J, 'rc':rc, 'Fermi_cut':Fermi_cut }}
|
|
405
|
+
"""
|
|
406
|
+
Ublock = []
|
|
407
|
+
for key, val in Udict.items():
|
|
408
|
+
Ublock.append(" %s %s " % (key, 1))
|
|
409
|
+
if val["n"] is not None:
|
|
410
|
+
Ublock.append(" n=%s %s" % (val["n"], val["l"]))
|
|
411
|
+
else:
|
|
412
|
+
Ublock.append("%s" % (val["l"]))
|
|
413
|
+
Ublock.append(" %s %s" % (val["U"], val["J"]))
|
|
414
|
+
if "rc" in val:
|
|
415
|
+
Ublock.append(" %s %s" % (val["rc"], val["Fermi_cut"]))
|
|
416
|
+
Ublock.append(" %s" % val["scale_factor"])
|
|
417
|
+
|
|
418
|
+
self.update_fdf_arguments(
|
|
419
|
+
{"LDAU.Proj": Ublock, "LDAU.ProjectorGenerationMethod": 2}
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
def set_Udict(self, Udict):
|
|
423
|
+
"""
|
|
424
|
+
Udict: e.g. {"Fe":{"n":3, "l":2, "U":3.0, "J":0.0}, ...}
|
|
425
|
+
or {"Fe":{[3, 2, 3, 0]}
|
|
426
|
+
|
|
427
|
+
"""
|
|
428
|
+
for specy, val in Udict.items():
|
|
429
|
+
if isinstance(val, dict):
|
|
430
|
+
self.add_Hubbard_U(specy, **val)
|
|
431
|
+
else:
|
|
432
|
+
self.add_Hubbard_U(specy, *val)
|
|
433
|
+
|
|
434
|
+
def write_Hubbard_block(self, f):
|
|
435
|
+
pass
|
|
436
|
+
|
|
437
|
+
def relax(
|
|
438
|
+
self,
|
|
439
|
+
atoms,
|
|
440
|
+
TypeOfRun="Broyden",
|
|
441
|
+
VariableCell=True,
|
|
442
|
+
ConstantVolume=False,
|
|
443
|
+
RelaxCellOnly=False,
|
|
444
|
+
MaxForceTol=0.001,
|
|
445
|
+
MaxStressTol=1,
|
|
446
|
+
NumCGSteps=40,
|
|
447
|
+
relaxed_file="relaxed.vasp",
|
|
448
|
+
):
|
|
449
|
+
pbc = atoms.get_pbc()
|
|
450
|
+
initial_magnetic_moments = atoms.get_initial_magnetic_moments()
|
|
451
|
+
self.update_fdf_arguments(
|
|
452
|
+
{
|
|
453
|
+
"MD.TypeOfRun": TypeOfRun,
|
|
454
|
+
"MD.VariableCell": VariableCell,
|
|
455
|
+
"MD.ConstantVolume": ConstantVolume,
|
|
456
|
+
"MD.RelaxCellOnly": RelaxCellOnly,
|
|
457
|
+
"MD.MaxForceTol": "%s eV/Ang" % MaxForceTol,
|
|
458
|
+
"MD.MaxStressTol": "%s GPa" % MaxStressTol,
|
|
459
|
+
"MD.NumCGSteps": NumCGSteps,
|
|
460
|
+
}
|
|
461
|
+
)
|
|
462
|
+
self.calculate(atoms)
|
|
463
|
+
# self.read(self.prefix + '.XV')
|
|
464
|
+
self.atoms = read_xv(os.path.join(self.directory, self.prefix + ".XV"))
|
|
465
|
+
self.atoms.set_pbc(pbc)
|
|
466
|
+
self.atoms.set_initial_magnetic_moments(initial_magnetic_moments)
|
|
467
|
+
atoms = self.atoms
|
|
468
|
+
self.update_fdf_arguments(
|
|
469
|
+
{
|
|
470
|
+
"MD.NumCGSteps": 0,
|
|
471
|
+
}
|
|
472
|
+
)
|
|
473
|
+
if relaxed_file is not None:
|
|
474
|
+
write(relaxed_file, atoms, vasp5=True, sort=False)
|
|
475
|
+
return self.atoms
|
|
476
|
+
|
|
477
|
+
def scf_calculation(self, atoms, dos=True, kpts=[7, 7, 7], **kwargs):
|
|
478
|
+
if dos:
|
|
479
|
+
k1, k2, k3 = kpts
|
|
480
|
+
self.update_fdf_arguments(
|
|
481
|
+
{
|
|
482
|
+
"WriteEigenvalues": ".true.",
|
|
483
|
+
"ProjectedDensityOfStates": ["-70.00 30.0 0.015 3000 eV"],
|
|
484
|
+
"PDOS.kgrid_Monkhorst_Pack": [
|
|
485
|
+
f"{k1} 0 0 0.0",
|
|
486
|
+
f"0 {k2} 0 0.0",
|
|
487
|
+
f"0 0 {k3} 0.0",
|
|
488
|
+
],
|
|
489
|
+
}
|
|
490
|
+
)
|
|
491
|
+
self.calculate(atoms, **kwargs)
|
|
492
|
+
|
|
493
|
+
def _write_structure(self, f, atoms):
|
|
494
|
+
"""Translate the Atoms object to fdf-format.
|
|
495
|
+
|
|
496
|
+
Parameters:
|
|
497
|
+
- f: An open file object.
|
|
498
|
+
- atoms: An atoms object.
|
|
499
|
+
"""
|
|
500
|
+
cell = atoms.cell
|
|
501
|
+
f.write("\n")
|
|
502
|
+
|
|
503
|
+
if cell.rank in [1, 2]:
|
|
504
|
+
raise ValueError(
|
|
505
|
+
"Expected 3D unit cell or no unit cell. You may "
|
|
506
|
+
"wish to add vacuum along some directions."
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Write lattice vectors
|
|
510
|
+
if np.any(cell):
|
|
511
|
+
f.write(format_fdf("LatticeConstant", "1.0 Ang"))
|
|
512
|
+
f.write("%block LatticeVectors\n")
|
|
513
|
+
for i in range(3):
|
|
514
|
+
for j in range(3):
|
|
515
|
+
s = (" %.15f" % cell[i, j]).rjust(16) + " "
|
|
516
|
+
f.write(s)
|
|
517
|
+
f.write("\n")
|
|
518
|
+
f.write("%endblock LatticeVectors\n")
|
|
519
|
+
f.write("\n")
|
|
520
|
+
|
|
521
|
+
self._write_atomic_coordinates(f, atoms)
|
|
522
|
+
|
|
523
|
+
# Write magnetic moments.
|
|
524
|
+
magmoms = atoms.get_initial_magnetic_moments()
|
|
525
|
+
|
|
526
|
+
# The DM.InitSpin block must be written to initialize to
|
|
527
|
+
# no spin. SIESTA default is FM initialization, if the
|
|
528
|
+
# block is not written, but we must conform to the
|
|
529
|
+
# atoms object.
|
|
530
|
+
if magmoms is not None:
|
|
531
|
+
if len(magmoms) == 0:
|
|
532
|
+
f.write("#Empty block forces ASE initialization.\n")
|
|
533
|
+
|
|
534
|
+
f.write("%block DM.InitSpin\n")
|
|
535
|
+
if len(magmoms) != 0 and isinstance(magmoms[0], np.ndarray):
|
|
536
|
+
for n, Mcart in enumerate(magmoms):
|
|
537
|
+
M = cart2sph(Mcart)
|
|
538
|
+
if M[0] != 0:
|
|
539
|
+
f.write(
|
|
540
|
+
" %d %.14f %.14f %.14f \n" % (n + 1, M[0], M[1], M[2])
|
|
541
|
+
)
|
|
542
|
+
elif len(magmoms) != 0 and isinstance(magmoms[0], float):
|
|
543
|
+
for n, M in enumerate(magmoms):
|
|
544
|
+
if M != 0:
|
|
545
|
+
f.write(" %d %.14f \n" % (n + 1, M))
|
|
546
|
+
f.write("%endblock DM.InitSpin\n")
|
|
547
|
+
f.write("\n")
|
|
548
|
+
|
|
549
|
+
def my_read_results(self):
|
|
550
|
+
"""Read the results."""
|
|
551
|
+
# self.read_number_of_grid_points()
|
|
552
|
+
self.read_energy()
|
|
553
|
+
self.read_forces_stress()
|
|
554
|
+
# self.read_eigenvalues()
|
|
555
|
+
self.read_kpoints()
|
|
556
|
+
self.read_dipole()
|
|
557
|
+
self.read_pseudo_density()
|
|
558
|
+
# self.read_hsx()
|
|
559
|
+
self.read_dim()
|
|
560
|
+
# if self.results['hsx'] is not None:
|
|
561
|
+
# self.read_pld(self.results['hsx'].norbitals,
|
|
562
|
+
# len(self.atoms))
|
|
563
|
+
# self.atoms.cell = self.results['pld'].cell * Bohr
|
|
564
|
+
# else:
|
|
565
|
+
# self.results['pld'] = None
|
|
566
|
+
|
|
567
|
+
# self.read_wfsx()
|
|
568
|
+
self.read_ion(self.atoms)
|
|
569
|
+
|
|
570
|
+
self.read_bands()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
withf_basis = {
|
|
2
|
+
# "La": "5\nn=5 0 1\n3.889 \n1.0 \nn=6 0 2\n9.113 6.906 \n1.0 1.0 \nn=5 1 1\n4.548 \n1.0 \nn=6 1 1\n9.113 \n1.0 \nn=5 2 2\n7.55 5.398 \n1.0 1.0 \n",
|
|
3
|
+
"Ce": "6\nn=5 0 1\n3.805 \n1.0 \nn=6 0 2\n9.041 6.837 \n1.0 1.0 \nn=5 1 1\n4.458 \n1.0 \nn=6 1 1\n9.041 \n1.0 \nn=5 2 2\n7.489 5.339 \n1.0 1.0 \nn=4 3 2\n4.114 2.494 \n1.0 1.0 \n",
|
|
4
|
+
"Pr": "6\nn=5 0 1\n3.737 \n1.0 \nn=6 0 2\n8.879 6.702 \n1.0 1.0 \nn=5 1 1\n4.387 \n1.0 \nn=6 1 1\n8.879 \n1.0 \nn=5 2 2\n7.46 5.307 \n1.0 1.0 \nn=4 3 2\n3.944 2.369 \n1.0 1.0 \n",
|
|
5
|
+
"Nd": "6\nn=5 0 1\n3.67 \n1.0 \nn=6 0 2\n8.808 6.641 \n1.0 1.0 \nn=5 1 1\n4.317 \n1.0 \nn=6 1 1\n8.808 \n1.0 \nn=5 2 2\n7.445 5.285 \n1.0 1.0 \nn=4 3 2\n3.805 2.271 \n1.0 1.0 \n",
|
|
6
|
+
"Pm": "6\nn=5 0 1\n3.611 \n1.0 \nn=6 0 2\n8.756 6.588 \n1.0 1.0 \nn=5 1 1\n4.257 \n1.0 \nn=6 1 1\n8.756 \n1.0 \nn=5 2 2\n7.43 5.269 \n1.0 1.0 \nn=4 3 2\n3.692 2.189 \n1.0 1.0 \n",
|
|
7
|
+
"Sm": "6\nn=5 0 1\n3.554 \n1.0 \nn=6 0 2\n8.668 6.516 \n1.0 1.0 \nn=5 1 1\n4.197 \n1.0 \nn=6 1 1\n8.668 \n1.0 \nn=5 2 2\n7.445 5.269 \n1.0 1.0 \nn=4 3 2\n3.59 2.115 \n1.0 1.0 \n",
|
|
8
|
+
"Eu": "6\nn=5 0 1\n3.497 \n1.0 \nn=6 0 2\n8.599 6.458 \n1.0 1.0 \nn=5 1 1\n4.139 \n1.0 \nn=6 1 1\n8.599 \n1.0 \nn=5 2 2\n7.46 5.275 \n1.0 1.0 \nn=4 3 2\n3.504 2.052 \n1.0 1.0 \n",
|
|
9
|
+
"Gd": "6\nn=5 0 1\n3.442 \n1.0 \nn=6 0 2\n8.514 6.374 \n1.0 1.0 \nn=5 1 1\n4.089 \n1.0 \nn=6 1 1\n8.514 \n1.0 \nn=5 2 2\n7.489 5.285 \n1.0 1.0 \nn=4 3 2\n3.435 1.997 \n1.0 1.0 \n",
|
|
10
|
+
"Tb": "6\nn=5 0 1\n3.394 \n1.0 \nn=6 0 2\n8.395 6.279 \n1.0 1.0 \nn=5 1 1\n4.04 \n1.0 \nn=6 1 1\n8.395 \n1.0 \nn=5 2 2\n7.52 5.301 \n1.0 1.0 \nn=4 3 2\n3.366 1.948 \n1.0 1.0 \n",
|
|
11
|
+
"Dy": "6\nn=5 0 1\n3.346 \n1.0 \nn=6 0 2\n8.295 6.186 \n1.0 1.0 \nn=5 1 1\n3.992 \n1.0 \nn=6 1 1\n8.295 \n1.0 \nn=5 2 2\n7.565 5.323 \n1.0 1.0 \nn=4 3 2\n3.306 1.901 \n1.0 1.0 \n",
|
|
12
|
+
"Ho": "6\nn=5 0 1\n3.293 \n1.0 \nn=6 0 2\n8.179 6.093 \n1.0 1.0 \nn=5 1 1\n3.944 \n1.0 \nn=6 1 1\n8.179 \n1.0 \nn=5 2 2\n7.61 5.349 \n1.0 1.0 \nn=4 3 2\n3.254 1.86 \n1.0 1.0 \n",
|
|
13
|
+
"Er": "6\nn=5 0 1\n3.247 \n1.0 \nn=6 0 2\n8.049 5.972 \n1.0 1.0 \nn=5 1 1\n3.897 \n1.0 \nn=6 1 1\n8.049 \n1.0 \nn=5 2 2\n7.656 5.387 \n1.0 1.0 \nn=4 3 2\n3.208 1.821 \n1.0 1.0 \n",
|
|
14
|
+
"Tm": "6\nn=5 0 1\n3.202 \n1.0 \nn=6 0 2\n7.921 5.872 \n1.0 1.0 \nn=5 1 1\n3.858 \n1.0 \nn=6 1 1\n7.921 \n1.0 \nn=5 2 2\n7.718 5.419 \n1.0 1.0 \nn=4 3 2\n3.163 1.785 \n1.0 1.0 \n",
|
|
15
|
+
"Yb": "6\nn=5 0 1\n3.163 \n1.0 \nn=6 0 2\n7.796 5.761 \n1.0 1.0 \nn=5 1 1\n3.812 \n1.0 \nn=6 1 1\n7.796 \n1.0 \nn=5 2 2\n7.78 5.468 \n1.0 1.0 \nn=4 3 2\n3.119 1.753 \n1.0 1.0 \n",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fincore_basis = {
|
|
19
|
+
# "La": "4\nn=5 0 1\n3.889 \n1.0 \nn=6 0 2\n9.113 6.906 \n1.0 1.0 \nn=5 1 1\n4.548 \n1.0 \nn=6 1 1\n9.113 \n1.0 \nn=5 2 2\n7.55 5.398 \n1.0 1.0 \n",
|
|
20
|
+
"Ce": "5\nn=5 0 1\n3.805 \n1.0 \nn=6 0 2\n8.968 6.776 \n1.0 1.0 \nn=5 1 1\n4.458 \n1.0 \nn=6 1 1\n8.968 \n1.0 \nn=5 2 2\n7.489 5.339 \n1.0 1.0 \n",
|
|
21
|
+
"Pr": "5\nn=5 0 1\n3.737 \n1.0 \nn=6 0 2\n8.791 6.621 \n1.0 1.0 \nn=5 1 1\n4.387 \n1.0 \nn=6 1 1\n8.791 \n1.0 \nn=5 2 2\n7.46 5.307 \n1.0 1.0 \n",
|
|
22
|
+
"Nd": "5\nn=5 0 1\n3.67 \n1.0 \nn=6 0 2\n8.634 6.49 \n1.0 1.0 \nn=5 1 1\n4.317 \n1.0 \nn=6 1 1\n8.634 \n1.0 \nn=5 2 2\n7.445 5.285 \n1.0 1.0 \n",
|
|
23
|
+
"Pm": "5\nn=5 0 1\n3.611 \n1.0 \nn=6 0 2\n8.446 6.33 \n1.0 1.0 \nn=5 1 1\n4.257 \n1.0 \nn=6 1 1\n8.446 \n1.0 \nn=5 2 2\n7.43 5.269 \n1.0 1.0 \n",
|
|
24
|
+
"Sm": "5\nn=5 0 1\n3.554 \n1.0 \nn=6 0 2\n8.328 6.223 \n1.0 1.0 \nn=5 1 1\n4.197 \n1.0 \nn=6 1 1\n8.328 \n1.0 \nn=5 2 2\n7.445 5.269 \n1.0 1.0 \n",
|
|
25
|
+
"Eu": "5\nn=5 0 1\n3.497 \n1.0 \nn=6 0 2\n8.278 6.186 \n1.0 1.0 \nn=5 1 1\n4.139 \n1.0 \nn=6 1 1\n8.278 \n1.0 \nn=5 2 2\n7.46 5.275 \n1.0 1.0 \n",
|
|
26
|
+
"Gd": "5\nn=5 0 1\n3.442 \n1.0 \nn=6 0 2\n8.278 6.179 \n1.0 1.0 \nn=5 1 1\n4.089 \n1.0 \nn=6 1 1\n8.278 \n1.0 \nn=5 2 2\n7.489 5.285 \n1.0 1.0 \n",
|
|
27
|
+
"Tb": "5\nn=5 0 1\n3.394 \n1.0 \nn=6 0 2\n8.147 6.063 \n1.0 1.0 \nn=5 1 1\n4.04 \n1.0 \nn=6 1 1\n8.147 \n1.0 \nn=5 2 2\n7.52 5.301 \n1.0 1.0 \n",
|
|
28
|
+
"Dy": "5\nn=5 0 1\n3.346 \n1.0 \nn=6 0 2\n7.969 5.919 \n1.0 1.0 \nn=5 1 1\n3.992 \n1.0 \nn=6 1 1\n7.969 \n1.0 \nn=5 2 2\n7.565 5.323 \n1.0 1.0 \n",
|
|
29
|
+
"Ho": "5\nn=5 0 1\n3.293 \n1.0 \nn=6 0 2\n7.827 5.79 \n1.0 1.0 \nn=5 1 1\n3.944 \n1.0 \nn=6 1 1\n7.827 \n1.0 \nn=5 2 2\n7.61 5.349 \n1.0 1.0 \n",
|
|
30
|
+
"Er": "5\nn=5 0 1\n3.247 \n1.0 \nn=6 0 2\n7.626 5.624 \n1.0 1.0 \nn=5 1 1\n3.897 \n1.0 \nn=6 1 1\n7.626 \n1.0 \nn=5 2 2\n7.656 5.387 \n1.0 1.0 \n",
|
|
31
|
+
"Tm": "5\nn=5 0 1\n3.202 \n1.0 \nn=6 0 2\n7.474 5.49 \n1.0 1.0 \nn=5 1 1\n3.858 \n1.0 \nn=6 1 1\n7.474 \n1.0 \nn=5 2 2\n7.718 5.419 \n1.0 1.0 \n",
|
|
32
|
+
"Yb": "5\nn=5 0 1\n3.163 \n1.0 \nn=6 0 2\n7.312 5.36 \n1.0 1.0 \nn=5 1 1\n3.812 \n1.0 \nn=6 1 1\n7.312 \n1.0 \nn=5 2 2\n7.78 5.468 \n1.0 1.0 \n",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_basis(element, fincore=False):
|
|
37
|
+
if not fincore:
|
|
38
|
+
return withf_basis[element]
|
|
39
|
+
else:
|
|
40
|
+
return fincore_basis[element]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
print(get_basis("La"))
|
|
45
|
+
print(get_basis("La", fincore=True))
|
|
46
|
+
print(get_basis("Ce"))
|
|
47
|
+
print(get_basis("Ce", fincore=True))
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Spin-phonon coupling calculation workflow using SIESTA and TB2J.
|
|
4
|
+
|
|
5
|
+
This module generates distorted structures from phonon modes and computes
|
|
6
|
+
exchange parameters for each structure.
|
|
7
|
+
|
|
8
|
+
Purpose:
|
|
9
|
+
Compute exchange parameters as a function of phonon mode amplitude
|
|
10
|
+
to study spin-phonon coupling.
|
|
11
|
+
|
|
12
|
+
How to run:
|
|
13
|
+
python -m TB2Jflows.siesta_spinphonon
|
|
14
|
+
|
|
15
|
+
Expected behavior:
|
|
16
|
+
For each amplitude, generates a distorted structure and runs SIESTA+TB2J
|
|
17
|
+
to compute exchange parameters.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Callable, List, Optional, Union
|
|
22
|
+
|
|
23
|
+
# Import from phononkit
|
|
24
|
+
from phononkit import generate_structure_for_mode, load_from_phonopy_yaml
|
|
25
|
+
|
|
26
|
+
from TB2Jflows import auto_siesta_TB2J
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compute_spinphonon_coupling(
|
|
30
|
+
phonon_yaml: str,
|
|
31
|
+
qpoint: list,
|
|
32
|
+
mode_index: int,
|
|
33
|
+
amplitudes: list,
|
|
34
|
+
supercell: Union[List[int], List[List[int]], None] = None,
|
|
35
|
+
base_path: str = "./spinphonon_results",
|
|
36
|
+
spin: str = "collinear",
|
|
37
|
+
magnetic_elements: Optional[List[str]] = None,
|
|
38
|
+
Udict: Optional[dict] = None,
|
|
39
|
+
xc: str = "PBE",
|
|
40
|
+
kmesh: Optional[List[int]] = None,
|
|
41
|
+
relax: bool = False,
|
|
42
|
+
scf: bool = True,
|
|
43
|
+
TB2J: bool = True,
|
|
44
|
+
rotate_type: str = "structure",
|
|
45
|
+
fincore: bool = True,
|
|
46
|
+
siesta_kwargs: Optional[dict] = None,
|
|
47
|
+
TB2J_kwargs: Optional[dict] = None,
|
|
48
|
+
fdf_kwargs: Optional[dict] = None,
|
|
49
|
+
prepare_atoms_callback: Optional[Callable] = None,
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Compute exchange parameters for phonon-distorted structures.
|
|
53
|
+
|
|
54
|
+
This function generates distorted structures from a phonon mode at different
|
|
55
|
+
amplitudes and computes exchange parameters using SIESTA and TB2J for each.
|
|
56
|
+
|
|
57
|
+
Parameters:
|
|
58
|
+
phonon_yaml: Path to phonopy YAML file containing phonon data
|
|
59
|
+
qpoint: Q-point coordinates [qx, qy, qz] in reduced coordinates
|
|
60
|
+
(e.g., [0, 0, 0] for Gamma point)
|
|
61
|
+
mode_index: Index of the phonon mode at the specified q-point (0-based)
|
|
62
|
+
amplitudes: List of displacement amplitudes in Angstroms
|
|
63
|
+
(e.g., [0.1, 0.2, 0.3, 0.4, 0.5])
|
|
64
|
+
supercell: Supercell specification (optional):
|
|
65
|
+
- 3-vector [n1, n2, n3] for diagonal matrix (e.g., [2, 2, 2])
|
|
66
|
+
- Full 3x3 matrix [[n1, 0, 0], [0, n2, 0], [0, 0, n3]]
|
|
67
|
+
- If None, uses primitive cell
|
|
68
|
+
base_path: Base directory for output files
|
|
69
|
+
spin: Spin type ('collinear', 'noncollinear', 'spinorbit')
|
|
70
|
+
magnetic_elements: List of magnetic element symbols (if None, auto-detect)
|
|
71
|
+
Udict: Dictionary of Hubbard U parameters {element: U_value}
|
|
72
|
+
xc: Exchange-correlation functional
|
|
73
|
+
kmesh: K-point mesh [nk1, nk2, nk3] (if None, auto-generate)
|
|
74
|
+
relax: Whether to perform structural relaxation
|
|
75
|
+
scf: Whether to run SCF calculation
|
|
76
|
+
TB2J: Whether to run TB2J calculation
|
|
77
|
+
rotate_type: Type of rotation for non-collinear calculations
|
|
78
|
+
fincore: Whether to use frozen core approximation
|
|
79
|
+
siesta_kwargs: Additional SIESTA parameters
|
|
80
|
+
TB2J_kwargs: Additional TB2J parameters
|
|
81
|
+
fdf_kwargs: Additional FDF file parameters
|
|
82
|
+
prepare_atoms_callback: Optional callback function to modify atoms
|
|
83
|
+
before calculation (e.g., set magnetic moments)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
dict: Dictionary mapping amplitudes to their calculation directories
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
>>> # Compute exchange for Gamma-point mode 3 at various amplitudes
|
|
90
|
+
>>> results = compute_spinphonon_coupling(
|
|
91
|
+
... phonon_yaml='phonopy.yaml',
|
|
92
|
+
... qpoint=[0, 0, 0],
|
|
93
|
+
... mode_index=3,
|
|
94
|
+
... amplitudes=[0.1, 0.2, 0.3, 0.4, 0.5],
|
|
95
|
+
... supercell=[2, 2, 2],
|
|
96
|
+
... magnetic_elements=['Fe', 'Co'],
|
|
97
|
+
... Udict={'Fe': 4.0, 'Co': 4.5}
|
|
98
|
+
... )
|
|
99
|
+
|
|
100
|
+
>>> # Use results
|
|
101
|
+
>>> for amp, calc_dir in results.items():
|
|
102
|
+
... print(f"Amplitude {amp} Å: {calc_dir}")
|
|
103
|
+
"""
|
|
104
|
+
# Set defaults
|
|
105
|
+
if Udict is None:
|
|
106
|
+
Udict = {}
|
|
107
|
+
if siesta_kwargs is None:
|
|
108
|
+
siesta_kwargs = {}
|
|
109
|
+
if TB2J_kwargs is None:
|
|
110
|
+
TB2J_kwargs = {}
|
|
111
|
+
if fdf_kwargs is None:
|
|
112
|
+
fdf_kwargs = {}
|
|
113
|
+
|
|
114
|
+
# Create base directory
|
|
115
|
+
path_obj = Path(base_path)
|
|
116
|
+
path_obj.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
|
|
118
|
+
# Load phonon data to get the structure
|
|
119
|
+
print(f"Loading phonon data from: {phonon_yaml}")
|
|
120
|
+
structure, modes = load_from_phonopy_yaml(phonon_yaml)
|
|
121
|
+
|
|
122
|
+
# Auto-detect magnetic elements if not provided
|
|
123
|
+
if magnetic_elements is None:
|
|
124
|
+
# For now, assume all unique elements with initial magnetic moments
|
|
125
|
+
# User should provide this explicitly
|
|
126
|
+
magnetic_elements = list(set(structure.get_chemical_symbols()))
|
|
127
|
+
print(f"Warning: Auto-detected magnetic elements: {magnetic_elements}")
|
|
128
|
+
print("Consider providing magnetic_elements explicitly")
|
|
129
|
+
|
|
130
|
+
# Dictionary to store results
|
|
131
|
+
results = {}
|
|
132
|
+
|
|
133
|
+
# Loop over amplitudes
|
|
134
|
+
for amplitude in amplitudes:
|
|
135
|
+
print("=" * 70)
|
|
136
|
+
print(f"Processing amplitude: {amplitude} Å")
|
|
137
|
+
print("=" * 70)
|
|
138
|
+
|
|
139
|
+
# Generate distorted structure
|
|
140
|
+
print("Generating distorted structure...")
|
|
141
|
+
print(f" Q-point: {qpoint}")
|
|
142
|
+
print(f" Mode index: {mode_index}")
|
|
143
|
+
print(f" Amplitude: {amplitude} Å")
|
|
144
|
+
if supercell is not None:
|
|
145
|
+
print(f" Supercell: {supercell}")
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
distorted_atoms = generate_structure_for_mode(
|
|
149
|
+
yaml_path=phonon_yaml,
|
|
150
|
+
qpoint=qpoint,
|
|
151
|
+
mode_index=mode_index,
|
|
152
|
+
amplitude=amplitude,
|
|
153
|
+
supercell=supercell,
|
|
154
|
+
)
|
|
155
|
+
print(f" Generated structure with {len(distorted_atoms)} atoms")
|
|
156
|
+
|
|
157
|
+
# Apply callback if provided
|
|
158
|
+
if prepare_atoms_callback is not None:
|
|
159
|
+
distorted_atoms = prepare_atoms_callback(distorted_atoms)
|
|
160
|
+
|
|
161
|
+
except Exception as e:
|
|
162
|
+
print(f"Error generating structure for amplitude {amplitude}: {e}")
|
|
163
|
+
continue
|
|
164
|
+
|
|
165
|
+
# Create calculation directory
|
|
166
|
+
calc_dir = path_obj / f"amplitude_{amplitude:.4f}"
|
|
167
|
+
calc_dir.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
|
|
169
|
+
print(f"Running SIESTA+TB2J calculation in: {calc_dir}")
|
|
170
|
+
|
|
171
|
+
# Run auto_siesta_TB2J
|
|
172
|
+
try:
|
|
173
|
+
auto_siesta_TB2J(
|
|
174
|
+
path=str(calc_dir),
|
|
175
|
+
atoms=distorted_atoms,
|
|
176
|
+
spin=spin,
|
|
177
|
+
elems=magnetic_elements,
|
|
178
|
+
Udict=Udict,
|
|
179
|
+
xc=xc,
|
|
180
|
+
kmesh=kmesh,
|
|
181
|
+
split_soc=False,
|
|
182
|
+
relax=relax,
|
|
183
|
+
scf=scf,
|
|
184
|
+
TB2J=TB2J,
|
|
185
|
+
rotate_type=rotate_type,
|
|
186
|
+
fincore=fincore,
|
|
187
|
+
siesta_kwargs=siesta_kwargs,
|
|
188
|
+
TB2J_kwargs=TB2J_kwargs,
|
|
189
|
+
fdf_kwargs=fdf_kwargs,
|
|
190
|
+
)
|
|
191
|
+
results[amplitude] = str(calc_dir)
|
|
192
|
+
print(f"✓ Completed calculation for amplitude {amplitude} Å")
|
|
193
|
+
except Exception as e:
|
|
194
|
+
print(f"✗ Error running calculation for amplitude {amplitude}: {e}")
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
# Summary
|
|
198
|
+
print("\n" + "=" * 70)
|
|
199
|
+
print("Spin-Phonon Coupling Calculation Summary")
|
|
200
|
+
print("=" * 70)
|
|
201
|
+
print(f"Total amplitudes processed: {len(results)}/{len(amplitudes)}")
|
|
202
|
+
print(f"Results stored in: {path_obj}")
|
|
203
|
+
print("\nCompleted calculations:")
|
|
204
|
+
for amp, calc_dir in sorted(results.items()):
|
|
205
|
+
print(f" {amp:.4f} Å → {calc_dir}")
|
|
206
|
+
|
|
207
|
+
return results
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def main():
|
|
211
|
+
"""
|
|
212
|
+
Example usage of compute_spinphonon_coupling.
|
|
213
|
+
|
|
214
|
+
This example shows how to compute exchange parameters for a phonon mode
|
|
215
|
+
at multiple amplitudes. Users should modify the parameters below for
|
|
216
|
+
their specific calculation.
|
|
217
|
+
"""
|
|
218
|
+
# Example parameters - MODIFY THESE FOR YOUR CALCULATION
|
|
219
|
+
phonon_yaml = "phonopy.yaml"
|
|
220
|
+
qpoint = [0, 0, 0] # Gamma point
|
|
221
|
+
mode_index = 3 # Fourth mode (0-indexed)
|
|
222
|
+
amplitudes = [0.1, 0.2, 0.3, 0.4, 0.5] # Amplitudes in Angstroms
|
|
223
|
+
supercell = [2, 2, 2] # 2x2x2 supercell
|
|
224
|
+
magnetic_elements = ["Fe"] # Magnetic elements
|
|
225
|
+
Udict = {"Fe": 4.0} # Hubbard U parameters
|
|
226
|
+
|
|
227
|
+
compute_spinphonon_coupling(
|
|
228
|
+
phonon_yaml=phonon_yaml,
|
|
229
|
+
qpoint=qpoint,
|
|
230
|
+
mode_index=mode_index,
|
|
231
|
+
amplitudes=amplitudes,
|
|
232
|
+
supercell=supercell,
|
|
233
|
+
base_path="./spinphonon_results",
|
|
234
|
+
spin="collinear",
|
|
235
|
+
magnetic_elements=magnetic_elements,
|
|
236
|
+
Udict=Udict,
|
|
237
|
+
xc="PBE",
|
|
238
|
+
kmesh=None, # Auto-generate
|
|
239
|
+
relax=False,
|
|
240
|
+
scf=True,
|
|
241
|
+
TB2J=True,
|
|
242
|
+
rotate_type="structure",
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
print("\n" + "=" * 70)
|
|
246
|
+
print("Calculation complete!")
|
|
247
|
+
print("=" * 70)
|
|
248
|
+
print("Next steps:")
|
|
249
|
+
print("1. Check the results in the output directories")
|
|
250
|
+
print("2. Extract exchange parameters from TB2J output files")
|
|
251
|
+
print("3. Plot exchange parameters vs. amplitude to study spin-phonon coupling")
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
if __name__ == "__main__":
|
|
255
|
+
main()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: TB2Jflows
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: TB2Jflows: Workflows for automatically calculation of exchange parameters using TB2J
|
|
5
|
+
Author-email: Xu He <mailhexu@gmail.com>
|
|
6
|
+
License: BSD-2-clause
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Requires-Dist: ase
|
|
17
|
+
Requires-Dist: sisl
|
|
18
|
+
Requires-Dist: tb2j
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# TB2Jflows
|
|
22
|
+
Workflows for automatically calculation of exchange parameters from DFT
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
First download the package from the github page. Run the following command in the TB2Jflows directory
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
pip install . --user
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
will install TB2Jflows and the dependencies.
|
|
33
|
+
|
|
34
|
+
You need the following things to
|
|
35
|
+
|
|
36
|
+
- Siesta built with psml and netcdf.
|
|
37
|
+
- Pseudopotentials from PseudoDojo Dataset.
|
|
38
|
+
- Configure the command to run siesta and the path to the pseudopotentials, e.g.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
export ASE_IESTA_COMMAND="mpirun siesta < PREFIX.fdf > PREFIX.out 2> PREFIX.err"
|
|
42
|
+
export DOJO_PATH='$HOME/.local/pp/dojo'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
Below is an example of calculating the exchange parameters of SrMnO3:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from ase.io import read
|
|
51
|
+
from TB2Jflows import SiestaFlow
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def calculate_siesta_TB2J_SrMnO3():
|
|
55
|
+
atoms = read('SrMnO3.STRUCT_OUT')
|
|
56
|
+
atoms.set_initial_magnetic_moments([0, 3, 0, 0, 0])
|
|
57
|
+
flow = SiestaFlow(atoms,
|
|
58
|
+
spin='spin-orbit',
|
|
59
|
+
restart=True,
|
|
60
|
+
root_path='SrMnO3')
|
|
61
|
+
flow.write_metadata()
|
|
62
|
+
atoms = flow.relax(atoms)
|
|
63
|
+
flow.scf_calculation_with_rotations(atoms)
|
|
64
|
+
flow.run_TB2J(magnetic_elements='Mn',
|
|
65
|
+
nz=50,
|
|
66
|
+
kmesh=[7, 7, 7],
|
|
67
|
+
Rcut=18,
|
|
68
|
+
np=10,
|
|
69
|
+
use_cache=True)
|
|
70
|
+
flow.run_TB2J_merge()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == '__main__':
|
|
74
|
+
calculate_siesta_TB2J_SrMnO3()
|
|
75
|
+
~
|
|
76
|
+
```
|
|
77
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
TB2Jflows/__init__.py,sha256=hRwR95ChyiFkUTX2djY2hQI9ph7x2YIJxiOehvxe79I,242
|
|
2
|
+
TB2Jflows/ase_siesta.py,sha256=d8Li-zwUGlulT0haEIKLSSgsveMU6YzV0thrFnDhV2U,14359
|
|
3
|
+
TB2Jflows/auto_siesta_TB2J.py,sha256=c5dviznEbXyO3BJbh-LNBlC9efT7YbdC7ydWxyCJZ5E,3113
|
|
4
|
+
TB2Jflows/find_pp.py,sha256=Od8Zb-Rd0kDC6ALBa39knYFNVKfNxhZx9OLocOS8YUA,2435
|
|
5
|
+
TB2Jflows/mysiesta.py,sha256=IUgfNu_X9rmX_CkqNsHrwFk3Hp8o5Wlp7Fd19PaCZPw,19518
|
|
6
|
+
TB2Jflows/run_abacus.py,sha256=96tZ2n02FFLl8IZf4W_4TvkCcsd6oS1FVEIqhZpY76o,2692
|
|
7
|
+
TB2Jflows/siesta_basis.py,sha256=ysGZUfjwuoOGImj0k-pDicKKG_o6Me0hzJqf5p5x9MQ,5319
|
|
8
|
+
TB2Jflows/siesta_spinphonon.py,sha256=jgTTtyWoJMnhyEJdWMnJ7pjxc6EM_aKEeu_-EgbtUFs,9037
|
|
9
|
+
tb2jflows-0.2.0.dist-info/METADATA,sha256=3Sy89-TX_nkmlZOxbCekV4sVrreG5q-cl9iNm1iX6Ho,2170
|
|
10
|
+
tb2jflows-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
11
|
+
tb2jflows-0.2.0.dist-info/licenses/LICENSE,sha256=KNu68sa-XR_2jZJKhDcSnxoNve8jtHgkw_w9PjP1YOk,1315
|
|
12
|
+
tb2jflows-0.2.0.dist-info/RECORD,,
|
tb2jflows-0.2.dist-info/METADATA
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: TB2Jflows
|
|
3
|
-
Version: 0.2
|
|
4
|
-
Summary: TB2Jflows: Workflows for automatically calculation of exchange parameters using TB2J
|
|
5
|
-
Author: Xu He
|
|
6
|
-
Author-email: mailhexu@gmail.com
|
|
7
|
-
License: BSD-2-clause
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
13
|
-
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
14
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
-
Requires-Python: >=3.6
|
|
16
|
-
License-File: LICENSE
|
|
17
|
-
Requires-Dist: TB2J
|
|
18
|
-
Requires-Dist: ase
|
|
19
|
-
Requires-Dist: sisl
|
|
20
|
-
Requires-Dist: pyDFTutils
|
|
21
|
-
Dynamic: author
|
|
22
|
-
Dynamic: author-email
|
|
23
|
-
Dynamic: classifier
|
|
24
|
-
Dynamic: description
|
|
25
|
-
Dynamic: license
|
|
26
|
-
Dynamic: license-file
|
|
27
|
-
Dynamic: requires-dist
|
|
28
|
-
Dynamic: requires-python
|
|
29
|
-
Dynamic: summary
|
|
30
|
-
|
|
31
|
-
TB2Jflows: Workflows for automatically calculation of exchange parameters using TB2J
|
tb2jflows-0.2.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
TB2Jflows/__init__.py,sha256=0aRVj9v-u64LxJl7Cyxcr4YUjpeMkBGPuv-nJbxbHOg,100
|
|
2
|
-
TB2Jflows/ase_siesta.py,sha256=tHeiKWszra8sjcJ_7Pq0cOBUC1ZEluRNEeHGj35Oz6M,14476
|
|
3
|
-
TB2Jflows/auto_siesta_TB2J.py,sha256=o1A5Qf0Ru35BY5jwSAIQ2rPXD1mb572LEAQfgNfEVnM,3174
|
|
4
|
-
TB2Jflows/run_abacus.py,sha256=96tZ2n02FFLl8IZf4W_4TvkCcsd6oS1FVEIqhZpY76o,2692
|
|
5
|
-
tb2jflows-0.2.dist-info/licenses/LICENSE,sha256=KNu68sa-XR_2jZJKhDcSnxoNve8jtHgkw_w9PjP1YOk,1315
|
|
6
|
-
tb2jflows-0.2.dist-info/METADATA,sha256=l2Lsj-MqAlL7fizCsUsD94RaqGpg6D-F-1HtmaOesL8,967
|
|
7
|
-
tb2jflows-0.2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
|
8
|
-
tb2jflows-0.2.dist-info/top_level.txt,sha256=iYRLHB7ZeHb59fEZLnbqJDymBKWPqfVgmvqd9S51Txw,10
|
|
9
|
-
tb2jflows-0.2.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
TB2Jflows
|
|
File without changes
|