TB2Jflows 0.0.1__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 ADDED
@@ -0,0 +1,2 @@
1
+ from TB2Jflows.ase_siesta import SiestaFlow
2
+ from TB2Jflows.auto_siesta_TB2J import auto_siesta_TB2J
@@ -0,0 +1,425 @@
1
+ import copy
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import ase
7
+ from ase.io.jsonio import decode, encode
8
+ from pyDFTutils.siesta import MySiesta
9
+ from TB2J.interfaces import gen_exchange_siesta
10
+ from TB2J.io_merge import merge
11
+ from TB2J.rotate_atoms import rotate_atom_spin, rotate_atom_xyz
12
+
13
+
14
+ class SiestaFlow:
15
+ def __init__(
16
+ self,
17
+ atoms,
18
+ basis_set: str = "DZP",
19
+ xc: str = "PBEsol",
20
+ spin: str = "collinear",
21
+ kpts=[6, 6, 6],
22
+ Udict: dict = {},
23
+ root_path="./",
24
+ restart=True,
25
+ metadata={},
26
+ fdf_arguments={},
27
+ split_soc=False,
28
+ **kwargs,
29
+ ):
30
+ self.atoms = atoms
31
+ self.basis_set = basis_set
32
+ self.xc = xc
33
+ self.kpts = kpts
34
+ self.Udict = Udict
35
+ # default fdf arguments
36
+ self.fdf_arguments = {
37
+ "MaxSCFIterations": 350,
38
+ "SCF.Mixer.Method": "Pulay",
39
+ "SCF.Mixer.History": 16,
40
+ "SCF.Mixer.Weight": 0.4,
41
+ "SCF.Mix.Spin": "sum",
42
+ "SCF.DM.Tolerance": 1e-4,
43
+ "SCF.EDM.Tolerance": "1e-2 eV",
44
+ "SCF.H.Tolerance": "1e-3 eV",
45
+ "Diag.ParallelOverK": "True",
46
+ }
47
+ if fdf_arguments:
48
+ self.fdf_arguments.update(fdf_arguments)
49
+ self.spin = spin
50
+ self.root_path = root_path
51
+ self.restart = restart
52
+ self.kwargs = kwargs
53
+
54
+ # paths
55
+ self.metadata_path = os.path.join(self.root_path, "metadata.json")
56
+ if not os.path.exists(self.root_path):
57
+ os.makedirs(self.root_path)
58
+ self.relax_path = os.path.join(self.root_path, "relax")
59
+ self.scf_path = os.path.join(self.root_path, "scf")
60
+
61
+ self.relaxed_atoms = None
62
+ self.split_soc = split_soc
63
+ self.initialize_metadata(metadata)
64
+
65
+ def initialize_metadata(self, metadata):
66
+ """Initialize the metadata.
67
+ If already exist, read from it.
68
+
69
+ """
70
+ if (
71
+ self.restart
72
+ and os.path.exists(self.metadata_path)
73
+ and os.path.isfile(self.metadata_path)
74
+ ):
75
+ self.load_metadata()
76
+ else:
77
+ self.metadata = {
78
+ "root_path": self.root_path,
79
+ "calculator": "siesta",
80
+ "initial_atoms": encode(self.atoms),
81
+ "spin": self.spin,
82
+ "xc": self.xc,
83
+ "already_relaxed": False,
84
+ }
85
+ self.metadata.update(metadata)
86
+
87
+ def load_metadata(self):
88
+ with open(self.metadata_path, "r") as myfile:
89
+ self.metadata = json.load(myfile)
90
+ self.initial_atoms = decode(self.metadata["initial_atoms"])
91
+ if ("relaxed_atoms" in self.metadata) and (
92
+ self.metadata["relaxed_atoms"] is not None
93
+ ):
94
+ self.relaxed_atoms = decode(self.metadata["relaxed_atoms"])
95
+
96
+ def write_metadata(self):
97
+ with open(self.metadata_path, "w") as myfile:
98
+ json.dump(self.metadata, myfile)
99
+
100
+ def update_metadata(self, d):
101
+ self.initialize_metadata(d)
102
+ self.write_metadata()
103
+
104
+ @property
105
+ def spin(self):
106
+ return self._spin
107
+
108
+ @spin.setter
109
+ def spin(self, spin):
110
+ self._spin = spin
111
+ if spin == "spin-orbit":
112
+ self.fdf_arguments.update({"SCF.Mix": "hamiltonian", "WriteOrbMom": True})
113
+ else:
114
+ if "writeOrbMom" in self.fdf_arguments:
115
+ self.fdf_arguments.pop("WriteOrbMom")
116
+ if spin == "spin-orbit":
117
+ self.rel = "fr"
118
+ else:
119
+ self.rel = "sr"
120
+
121
+ def get_calculator(
122
+ self,
123
+ atoms: ase.Atoms,
124
+ path="./",
125
+ label="siesta",
126
+ fdf_arguments={},
127
+ ):
128
+ fdf_args = copy.deepcopy(self.fdf_arguments)
129
+ fdf_args.update(fdf_arguments)
130
+ calc = MySiesta(
131
+ atoms=atoms,
132
+ label=label,
133
+ xc=self.xc,
134
+ basis_set=self.basis_set,
135
+ kpts=self.kpts,
136
+ spin=self.spin,
137
+ fdf_arguments=fdf_args,
138
+ **self.kwargs,
139
+ )
140
+ if self.Udict:
141
+ # calc.set_Hubbard_U(self.Udict)
142
+ calc.set_Udict(self.Udict)
143
+ calc.directory = path
144
+ calc.atoms = atoms
145
+ return copy.deepcopy(calc)
146
+
147
+ def relax(
148
+ self,
149
+ atoms,
150
+ use_collinear=True,
151
+ path="./relax",
152
+ label="siesta",
153
+ TypeOfRun="Broyden",
154
+ VariableCell=True,
155
+ ConstantVolume=False,
156
+ RelaxCellOnly=False,
157
+ MaxForceTol=0.001,
158
+ MaxStressTol=0.1,
159
+ NumCGSteps=200,
160
+ ):
161
+ if (
162
+ self.restart
163
+ and self.metadata["already_relaxed"]
164
+ and self.relaxed_atoms is not None
165
+ ):
166
+ self.load_metadata()
167
+ atoms = self.relaxed_atoms
168
+ else:
169
+ old_spin = self.spin
170
+ if use_collinear:
171
+ self.spin = "collinear"
172
+ calc = self.get_calculator(atoms, path=self.relax_path, label=label)
173
+ calc.atoms = atoms
174
+ atoms = calc.relax(
175
+ atoms,
176
+ TypeOfRun=TypeOfRun,
177
+ VariableCell=VariableCell,
178
+ ConstantVolume=ConstantVolume,
179
+ RelaxCellOnly=RelaxCellOnly,
180
+ MaxForceTol=MaxForceTol,
181
+ MaxStressTol=MaxStressTol,
182
+ NumCGSteps=NumCGSteps,
183
+ )
184
+ self.spin = old_spin
185
+ self.relaxed_atoms = atoms
186
+ self.update_metadata(
187
+ {
188
+ "already_relaxed": True,
189
+ "relax_path": self.relax_path,
190
+ "relaxed_atoms": encode(self.relaxed_atoms),
191
+ }
192
+ )
193
+ return atoms
194
+
195
+ def scf_calculation(self, atoms, path="./scf", label="siesta"):
196
+ print(f"SCF calculation in {path}")
197
+ HS_args = {
198
+ "SaveHS": True,
199
+ #'CDF.Save': True,
200
+ #'CDF.Compress': 9,
201
+ }
202
+ calc = self.get_calculator(atoms, path=path, label=label, fdf_arguments=HS_args)
203
+ calc.get_potential_energy()
204
+
205
+ def scf_calculation_with_rotations(
206
+ self, atoms, label="siesta", rotate_type="structure"
207
+ ):
208
+ self.fdf_arguments["Spin.Fix"] = False
209
+ self.spin = "spin-orbit"
210
+ if rotate_type == "structure":
211
+ atoms_xyz = rotate_atom_xyz(atoms)
212
+ elif rotate_type == "spin":
213
+ atoms_xyz = rotate_atom_spin(atoms)
214
+ else:
215
+ raise NotImplementedError(f"rotate_type={rotate_type} is not implemented")
216
+ for ratoms, rot in zip(atoms_xyz, ("x", "y", "z")):
217
+ self.scf_calculation(
218
+ ratoms, path=os.path.join(self.scf_path, rot), label=label
219
+ )
220
+
221
+ def scf_calculation_single_noncollinear(self, atoms, label="siesta"):
222
+ self.fdf_arguments["Spin.Fix"] = False
223
+ self.scf_calculation(
224
+ atoms, path=os.path.join(self.scf_path, "single_noncollinear"), label=label
225
+ )
226
+
227
+ def scf_calculatoin_split_soc(self, atoms, label="siesta", nscf=False):
228
+ fdf_args = {
229
+ "SOC_split_SR_SO": True,
230
+ #"Spin.OrbitStrength": 3,
231
+ "SaveHS.so": True,
232
+ "SaveHS": True,
233
+ "Spin.Fix": False,
234
+ }
235
+ nscf_args={"SCF.DM.Converge": True,
236
+ "SCF.DM.Tolerance": 1e4,
237
+ "SCF.H.Converge": False,
238
+ "SCF.EDM.Converge": False,
239
+ "SCF.Mix.First": False,
240
+ "SCF.Mix": "density",
241
+ "MaxSCFIterations": 1,
242
+ }
243
+ if nscf:
244
+ fdf_args.update(nscf_args)
245
+
246
+ self.spin = "spin-orbit"
247
+ path = Path(self.scf_path) / "split_soc"
248
+ path.mkdir(parents=True, exist_ok=True)
249
+ collinear_path = Path(self.scf_path) / "collinear"
250
+ # density matrix from collinear calculation
251
+ # copy density matrix from collinear calculation
252
+ dmfile = collinear_path / f"{label}.DM"
253
+ if dmfile.exists():
254
+ dmfile_new = path / f"{label}.DM"
255
+ print(f"Copying {dmfile} to {dmfile_new}")
256
+ os.system(f"cp {dmfile} {dmfile_new}")
257
+ calc = self.get_calculator(
258
+ atoms, path=path, label=label, fdf_arguments=fdf_args
259
+ )
260
+ calc.get_potential_energy()
261
+
262
+ def scf_calculation_collinear(self, atoms, label="siesta"):
263
+ old_spin = self.spin
264
+ self.spin = "collinear"
265
+ self.scf_calculation(
266
+ atoms, path=os.path.join(self.scf_path, "collinear"), label=label
267
+ )
268
+ self.spin = old_spin
269
+
270
+ def run_TB2J_collinear(self, **kwargs):
271
+ path = os.path.join(self.scf_path, "collinear")
272
+ fdf_fname = os.path.join(path, "siesta.fdf")
273
+ gen_exchange_siesta(
274
+ fdf_fname=fdf_fname,
275
+ **kwargs,
276
+ output_path=os.path.join(self.root_path, "TB2J_results_collinear"),
277
+ )
278
+
279
+ def run_TB2J_single_noncollinear(self, **kwargs):
280
+ path = os.path.join(self.scf_path, "single_noncollinear")
281
+ fdf_fname = os.path.join(path, "siesta.fdf")
282
+ gen_exchange_siesta(
283
+ fdf_fname=fdf_fname,
284
+ **kwargs,
285
+ output_path=os.path.join(
286
+ self.root_path, "TB2J_results_single_noncollinear"
287
+ ),
288
+ )
289
+
290
+ def set_nonscf_params(self):
291
+ nscf_params={"SCF.DM.Converge": False,
292
+ "SCF.DM.Tolerance": 1e4,
293
+ "SCF.H.Converge": False,
294
+ "SCF.EDM.Converge": False,
295
+ "SCF.Mix.First": False,
296
+ "SCF.Mix": "density",
297
+ "MaxSCFIterations": 1,
298
+ }
299
+
300
+ def run_TB2J_split_soc(self, **kwargs):
301
+ path = os.path.join(self.scf_path, "split_soc")
302
+ fdf_fname = os.path.join(path, "siesta.fdf")
303
+ gen_exchange_siesta(
304
+ fdf_fname=fdf_fname,
305
+ read_H_soc=True,
306
+ **kwargs,
307
+ output_path=os.path.join(self.root_path, "TB2J_results_split_soc"),
308
+ )
309
+ # merge results
310
+ paths = [
311
+ os.path.join(self.root_path, f"TB2J_results_split_soc_{rot}")
312
+ for rot in ("x", "y", "z")
313
+ ]
314
+ merge(
315
+ *paths,
316
+ # method=rotate_type,
317
+ write_path=os.path.join(self.root_path, "TB2J_results_merged"),
318
+ )
319
+
320
+ def run_TB2J(self, skip=False, **kwargs):
321
+ paths = []
322
+ for rot in ("x", "y", "z"):
323
+ path = os.path.join(self.scf_path, rot)
324
+ paths.append(path)
325
+ TB2J_path = os.path.join(self.root_path, f"TB2J_results_{rot}")
326
+ if not (skip and os.path.exists(os.path.join(TB2J_path, "exchange.txt"))):
327
+ fdf_fname = os.path.join(path, "siesta.fdf")
328
+ gen_exchange_siesta(
329
+ fdf_fname=fdf_fname, **kwargs, output_path=TB2J_path
330
+ )
331
+
332
+ def run_TB2J_rotate_structure(self, skip=False, **kwargs):
333
+ paths = []
334
+ for rot in ("x", "y", "z"):
335
+ path = os.path.join(self.scf_path, rot)
336
+ paths.append(path)
337
+ TB2J_path = os.path.join(self.root_path, f"TB2J_results_{rot}")
338
+ if not (skip and os.path.exists(os.path.join(TB2J_path, "exchange.txt"))):
339
+ fdf_fname = os.path.join(path, "siesta.fdf")
340
+ gen_exchange_siesta(
341
+ fdf_fname=fdf_fname, **kwargs, output_path=TB2J_path
342
+ )
343
+
344
+ def run_TB2J_merge(self, rotate_type="structure"):
345
+ paths = [
346
+ os.path.join(self.root_path, f"TB2J_results_{rot}")
347
+ for rot in ("x", "y", "z")
348
+ ]
349
+ merge(
350
+ *paths,
351
+ # method=rotate_type,
352
+ write_path=os.path.join(self.root_path, "TB2J_results_merged"),
353
+ )
354
+
355
+ def runall_collinear(self, atoms, relax=True, scf=True, TB2J=True, **kwargs):
356
+ if relax:
357
+ atoms = self.relax(atoms)
358
+ if scf:
359
+ self.scf_calculation_collinear(atoms, label="siesta")
360
+ if TB2J:
361
+ self.run_TB2J_collinear(**kwargs)
362
+
363
+ def runall_nc(
364
+ self, atoms, relax=True, scf=True, TB2J=True, rotate_type="structure", **kwargs
365
+ ):
366
+ if relax:
367
+ atoms = self.relax(atoms)
368
+ if scf:
369
+ self.scf_calculation_with_rotations(
370
+ atoms, rotate_type=rotate_type, label="siesta"
371
+ )
372
+ if TB2J:
373
+ self.run_TB2J(**kwargs)
374
+ self.run_TB2J_merge(rotate_type=rotate_type)
375
+
376
+ def runall_split_soc(self, atoms, relax=True, scf=True, TB2J=True, **kwargs):
377
+ if relax:
378
+ atoms = self.relax(atoms)
379
+ if scf:
380
+ self.scf_calculatoin_split_soc(atoms, label="siesta")
381
+ if TB2J:
382
+ self.run_TB2J_split_soc(**kwargs)
383
+
384
+ def runall(
385
+ self, atoms, relax=True, scf=True, TB2J=True, rotate_type="structure", **kwargs
386
+ ):
387
+ if self.spin == "collinear":
388
+ self.runall_collinear(atoms, relax=relax, scf=scf, TB2J=TB2J, **kwargs)
389
+ elif self.spin == "spin-orbit+onsite":
390
+ self.runall_nc(
391
+ atoms,
392
+ relax=relax,
393
+ scf=scf,
394
+ TB2J=TB2J,
395
+ rotate_type=rotate_type,
396
+ **kwargs,
397
+ )
398
+
399
+ elif self.spin == "spin-orbit":
400
+ if self.split_soc:
401
+ self.runall_split_soc(atoms, relax=relax, scf=scf, TB2J=TB2J, **kwargs)
402
+ else:
403
+ self.runall_nc(
404
+ atoms,
405
+ relax=relax,
406
+ scf=scf,
407
+ TB2J=TB2J,
408
+ rotate_type=rotate_type,
409
+ **kwargs,
410
+ )
411
+ elif self.spin == "collinear+spin-orbit":
412
+ self.runall_collinear(atoms, relax=relax, scf=scf, TB2J=TB2J, **kwargs)
413
+ if self.split_soc:
414
+ self.runall_split_soc(atoms, relax=relax, scf=scf, TB2J=TB2J, **kwargs)
415
+ else:
416
+ self.runall_nc(
417
+ atoms,
418
+ relax=relax,
419
+ scf=scf,
420
+ TB2J=TB2J,
421
+ rotate_type=rotate_type,
422
+ **kwargs,
423
+ )
424
+ else:
425
+ raise NotImplementedError(f"spin={self.spin} is not implemented in runall")
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+ import numpy as np
3
+ from ase.io import read
4
+ from ase.units import Ry
5
+
6
+ from TB2Jflows import SiestaFlow
7
+
8
+
9
+ def atoms_mag_along_z(atoms, mag, toz=True):
10
+ symbols = atoms.get_chemical_symbols()
11
+ symbols = np.array(symbols)
12
+
13
+ norm = np.linalg.norm(mag, axis=1)
14
+ imaxmag = np.argmax(norm)
15
+ ipolarized = np.where(norm > 0.1)
16
+
17
+ elems = set(symbols[ipolarized])
18
+
19
+ # rotate to collinear
20
+ if toz:
21
+ m_col = np.zeros(mag.shape[0], dtype=float)
22
+ m_ref = mag[imaxmag]
23
+ for i, m in enumerate(mag):
24
+ mrot = m @ m_ref
25
+ n = np.linalg.norm(m)
26
+ m_col[i] = n if mrot > 0 else -n
27
+ atoms.set_initial_magnetic_moments(None)
28
+ else:
29
+ atoms.set_initial_magnetic_moments(mag)
30
+ return atoms, elems
31
+
32
+
33
+ def read_to_collinear_mag_atoms(name):
34
+ path = f"../structures/{name}"
35
+ mag = np.load(f"{path}/mag.npy")
36
+ atoms = read(f"{path}/POSCAR.vasp")
37
+ atoms, elems = atoms_mag_along_z(atoms, mag)
38
+ return atoms, elems
39
+
40
+
41
+ def auto_siesta_TB2J(
42
+ path,
43
+ atoms,
44
+ spin,
45
+ elems,
46
+ Udict={},
47
+ xc="PBE",
48
+ kmesh=None,
49
+ split_soc=False,
50
+ relax=False,
51
+ scf=True,
52
+ TB2J=True,
53
+ rotate_type="structure",
54
+ fincore=True,
55
+ siesta_kwargs={},
56
+ TB2J_kwargs={},
57
+ fdf_kwargs={},
58
+ ):
59
+ # mag_elems = list(elems)
60
+ symbols = atoms.get_chemical_symbols()
61
+ cell = atoms.get_cell_lengths_and_angles()
62
+ Uname = {}
63
+ sset = set()
64
+ for s in symbols:
65
+ if s not in sset:
66
+ sset.add(s)
67
+ Uname[s] = s + f".{len(sset)}"
68
+ if kmesh is None:
69
+ kmesh = [int(40 // cell[0] + 1), int(40 // cell[1] + 1), int(40 // cell[2] + 1)]
70
+
71
+ fdf_arguments = {
72
+ "SCF.DM.Tolerance": "0.0001",
73
+ "ElectronicTemperature": "100 K",
74
+ "SCF.Mixer.Weight": "0.1",
75
+ "SCF.Mixer.History": "16",
76
+ "SCF.Mix.Spin": "sum",
77
+ "DM.NumberPulay": "6",
78
+ "SCF.Mixer.Method": "Pulay",
79
+ "MaxSCFIterations": 500,
80
+ "SCF.MustConverge": "False",
81
+ "SCFMustConverge": "False",
82
+ "WriteMullikenPop": "1",
83
+ "MullikenInSCF": "True",
84
+ "WriteHirshfeldPop": "True",
85
+ "WriteVoronoiPop": "True",
86
+ "CDF.save": "True",
87
+ }
88
+ fdf_arguments.update(fdf_kwargs)
89
+ flow = SiestaFlow(
90
+ atoms=atoms,
91
+ xc=xc,
92
+ spin=spin,
93
+ restart=True,
94
+ root_path=path,
95
+ kpts=kmesh,
96
+ mesh_cutoff=600 * Ry,
97
+ energy_shift=0.1,
98
+ fdf_arguments=fdf_arguments,
99
+ fincore=fincore,
100
+ Udict=Udict,
101
+ split_soc=split_soc,
102
+ **siesta_kwargs,
103
+ )
104
+ flow.write_metadata()
105
+ flow.runall(
106
+ atoms,
107
+ relax=relax,
108
+ scf=scf,
109
+ TB2J=TB2J,
110
+ rotate_type=rotate_type,
111
+ magnetic_elements=elems,
112
+ **TB2J_kwargs,
113
+ )
114
+
115
+
116
+ if __name__ == "__main__":
117
+ atoms = None
118
+ elems = None
119
+ path = "./"
120
+ auto_siesta_TB2J(
121
+ path,
122
+ atoms,
123
+ spin="collinear",
124
+ elems=elems,
125
+ Udict={},
126
+ kmesh=None,
127
+ relax=False,
128
+ scf=True,
129
+ rotate_type="structure",
130
+ )
@@ -0,0 +1,120 @@
1
+ from ase import Atoms
2
+ from ase.calculators.abacus import Abacus, AbacusProfile
3
+ from pathlib import Path
4
+ import shutil
5
+
6
+ abacus = "/home/hexu/.local/bin/abacus"
7
+ profile = AbacusProfile(argv=["mpirun", "-n", "8", abacus])
8
+
9
+
10
+ def gen_atoms():
11
+ """
12
+ 2D Fe slab
13
+ """
14
+ atoms = Atoms(
15
+ "Fe", scaled_positions=[(0, 0, 0)], cell=(2.315, 2.315, 15), pbc=(1, 1, 1)
16
+ )
17
+ return atoms
18
+
19
+
20
+ def gen_atoms_x():
21
+ """
22
+ 2D Fe slab
23
+ """
24
+ atoms = Atoms(
25
+ "Fe", scaled_positions=[(0, 0, 0)], cell=(15, 2.315, 2.315), pbc=(1, 1, 1)
26
+ )
27
+ return atoms
28
+
29
+ pdir = "/home/hexu/.local/pp/abacus/ABACUS-orbitals-main/Dojo-NC-FR"
30
+
31
+ default_params = dict(
32
+ profile=profile,
33
+ directory="Fe_soc0_x",
34
+ pseudo_dir=f"{pdir}/Pseudopotential",
35
+ orbital_dir=f"{pdir}/Orbitals/Fe/Orbital_Fe_DZP",
36
+ pp={"Fe": "Fe.upf"},
37
+ basis={"Fe": "Fe_gga_10au_100Ry_4s2p2d1f.orb"},
38
+ calculation="scf",
39
+ xc="PBE",
40
+ kpts=(9, 9, 1),
41
+ nspin=4,
42
+ symmetry=0,
43
+ noncolin=1,
44
+ lspinorb=1,
45
+ ecutwfc=100,
46
+ scf_thr=1.0e-6,
47
+ init_chg="atomic",
48
+ out_mul=1,
49
+ out_chg=1,
50
+ out_dos=0,
51
+ out_band=0,
52
+ out_wfc_lcao=1,
53
+ out_mat_hs2=1, # output H(R) and S(R) matrix
54
+ ks_solver="scalapack_gvx",
55
+ scf_nmax=500,
56
+ out_bandgap=0,
57
+ basis_type="lcao",
58
+ gamma_only=0,
59
+ smearing_method="gaussian",
60
+ smearing_sigma=0.01,
61
+ mixing_type="broyden",
62
+ mixing_beta=0.5,
63
+ soc_lambda=1.0,
64
+ )
65
+
66
+ params_nosoc = default_params.copy()
67
+ params_nosoc.update(dict(
68
+ soc_lambda=0.0,
69
+ noncolin=1,
70
+ ))
71
+
72
+ params_soc_nscf = default_params.copy()
73
+ params_soc_nscf.update(dict(
74
+ calculation="scf",
75
+ soc_lambda=1.0,
76
+ init_chg="file",
77
+ init_wfc="file",
78
+ out_chg=0,
79
+ out_wfc_lcao=0,
80
+ scf_nmax=1,
81
+ mixing_beta=1e-6,
82
+ scf_thr=1e6,
83
+ ))
84
+
85
+
86
+ def run_abacus(root="Fe_x", M=[[3, 0, 0]]):
87
+ atoms = gen_atoms()
88
+ atoms.set_initial_magnetic_moments(M)
89
+
90
+ path0=Path(root)/"soc0"
91
+ path1=Path(root)/"soc1"
92
+
93
+ params = params_nosoc.copy()
94
+ params.update(directory=path0)
95
+
96
+ calc = Abacus(**params)
97
+ atoms.set_calculator(calc)
98
+ atoms.get_potential_energy()
99
+
100
+ path1.mkdir(parents=True, exist_ok=True)
101
+ if (path1/"OUT.ABACUS").exists():
102
+ shutil.rmtree(str(path1/"OUT.ABACUS"))
103
+ shutil.copytree(str(path0/"OUT.ABACUS"), str(path1/"OUT.ABACUS"))
104
+
105
+ params = params_soc_nscf.copy()
106
+ params.update(directory=path1)
107
+ calc = Abacus(**params)
108
+ atoms.set_calculator(calc)
109
+ atoms.get_potential_energy()
110
+
111
+
112
+ def main():
113
+ run_abacus("Fe_x", [[3, 0, 0]])
114
+ run_abacus("Fe_z", [[0, 0, 3]])
115
+ run_abacus("Fe_-z", [[0, 0, -3]])
116
+ run_abacus("Fe_-x", [[-3, 0, 0]])
117
+
118
+
119
+ if __name__ == "__main__":
120
+ main()
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2020, Xu He
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,30 @@
1
+ Metadata-Version: 2.2
2
+ Name: TB2Jflows
3
+ Version: 0.0.1
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: requires-dist
27
+ Dynamic: requires-python
28
+ Dynamic: summary
29
+
30
+ TB2Jflows: Workflows for automatically calculation of exchange parameters using TB2J
@@ -0,0 +1,9 @@
1
+ TB2Jflows/__init__.py,sha256=0aRVj9v-u64LxJl7Cyxcr4YUjpeMkBGPuv-nJbxbHOg,100
2
+ TB2Jflows/ase_siesta.py,sha256=BagiujWCwUZ6Aj03oRFdAL1DzJ4pw1_upW4G5d9tMXw,14363
3
+ TB2Jflows/auto_siesta_TB2J.py,sha256=c5dviznEbXyO3BJbh-LNBlC9efT7YbdC7ydWxyCJZ5E,3113
4
+ TB2Jflows/run_abacus.py,sha256=96tZ2n02FFLl8IZf4W_4TvkCcsd6oS1FVEIqhZpY76o,2692
5
+ tb2jflows-0.0.1.dist-info/LICENSE,sha256=KNu68sa-XR_2jZJKhDcSnxoNve8jtHgkw_w9PjP1YOk,1315
6
+ tb2jflows-0.0.1.dist-info/METADATA,sha256=avwrwge2xfv6PgTUy92JCpBdqUFrJNbiNlQpurzX7Ss,947
7
+ tb2jflows-0.0.1.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
8
+ tb2jflows-0.0.1.dist-info/top_level.txt,sha256=iYRLHB7ZeHb59fEZLnbqJDymBKWPqfVgmvqd9S51Txw,10
9
+ tb2jflows-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (76.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ TB2Jflows