-
Notifications
You must be signed in to change notification settings - Fork 2
/
generate_inputs.py
executable file
·196 lines (172 loc) · 8.54 KB
/
generate_inputs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/env python
import copy
import sys
import os
import argparse
import shutil
from pymatgen.io.vasp.sets import MPStaticSet, MPSOCSet
from pymatgen.io.vasp.outputs import Outcar
from pymatgen.io.vasp.inputs import Incar
from pymatgen.transformations.site_transformations import TranslateSitesTransformation
from pymatgen.core.structure import Structure
from pymatgen.core.lattice import Lattice
def move_all_atoms(structure, disp_ion):
"""
Create structures with displaced ions
"""
yield 'calc_00_0', structure
atoms = [i for i in range(len(structure))]
for atom in atoms:
for direction in range(3):
displacement = [0.]*3
displacement[direction] = disp_ion
for orientation in ['+', '-']:
transform = TranslateSitesTransformation([atom], displacement, vector_in_frac_coords=True)
structure_displaced = transform.apply_transformation(structure)
yield 'calc_%02d_%s%d' % (atom+1, orientation, direction+1), structure_displaced
displacement[direction] = -displacement[direction]
def move_all_lattice(structure, disp_lattice):
"""
Create structures with displaced lattice
"""
for axnum, axname in enumerate(['a', 'b', 'c']):
for dirnum, dirname in enumerate(['X', 'Y', 'Z']):
for orientation in ['+', '-']:
structure_displaced = copy.deepcopy(structure)
structure_displaced.lattice.matrix[axnum, dirnum] += disp_lattice
yield 'calc_00_%s%s%s' % (axname, orientation, dirname), structure_displaced
disp_lattice = -disp_lattice
def generate_scf_folders(structures, user_incar):
"""
Generate calculations from the structures dictionary
"""
for name in structures:
if os.path.exists(name)==False:
os.mkdir(name)
structures[name].to(fmt='POSCAR', filename='/'.join([name, 'POSCAR']))
MPStaticSet(structures[name], user_incar_settings=user_incar, user_kpoints_settings={"reciprocal_density": 500}).write_input(name)
print(name+'\n')
def check_files(structures, filename):
"""
Check that filename exists and not empty in all structures folders
"""
calcs_failed = []
for name in structures:
f = os.path.join(name, filename)
if os.path.exists(f) == False or os.path.getsize(f) < 1000:
calcs_failed.append(name)
return(calcs_failed)
def generate_old_polarization_folders(structures):
"""
Generate the polarization calculations (old format) from the completed scf calculation
"""
for name in structures:
for i in range(3):
# compute the Berry phase along the x-i, y- and z-directions (IGPAR = 1,2,3)
# Note: calculations usualy are very sensetive to the choice of "NPPSTR" parameter. You might consider to reduce it.
MPStaticSet.from_prev_calc(name, user_incar_settings={"LBERRY":True,"IGPAR":i+1,"ICHARG":2,"NPAR":2,"ALGO":"Fast","NPPSTR":6,"LAECHG":False,"LVHAR":False, "ISIF": 2}, user_kpoints_settings={"reciprocal_density": 500}).write_input(os.path.join(name,'Berry_'+str(i+1)))
shutil.copy(os.path.join(name,'CHGCAR'), os.path.join(name,'Berry_'+str(i+1)))
def generate_new_polarization_folders(structures):
"""
Generate the polarization calculations (new format) from the completed scf calculation
"""
for name in structures:
MPStaticSet.from_prev_calc(name, user_incar_settings={"LCALCPOL":True,"LAECHG":False,"LVHAR":False, "ISIF": 2}, user_kpoints_settings={"reciprocal_density": 500}).write_input(os.path.join(name,'Berry_new'))
shutil.copy(os.path.join(name,'CHGCAR'), os.path.join(name,'Berry_new'))
def generate_nscf_soc_folders(structures, saxis, user_incar):
"""
Generate the non self-consistent calculation with the spin-orbit coupling
"""
for name in structures:
# add magmom as a site property for each atom
outcar = Outcar(filename=os.path.join(name,'OUTCAR'))
for i, atom in enumerate(structures[name].sites):
atom.properties={"magmom":[0.,0., round(outcar.magnetization[i]['tot'],2)]}
# geterate calculation from the MPSOCSet
mpsoc = MPSOCSet(structures[name], saxis=saxis, user_incar_settings=user_incar, user_kpoints_settings={"reciprocal_density": 500})
mpsoc.write_input(os.path.join(name,'nscf_SOC'))
# walk around the bug in MPSICSet to introduce LDAUU and LDAUL into INCAR
dic=mpsoc.incar.as_dict()
dic["LDAUU"]= list(dic["LDAUU"].values())
dic["LDAUL"]= list(dic["LDAUL"].values())
Incar.from_dict(dic).write_file(os.path.join(name,'nscf_SOC/INCAR'))
shutil.copy(os.path.join(name,'CHGCAR'), os.path.join(name,'nscf_SOC'))
class FDTcalculations(object):
"""
This class generates the self-consistent calculations for FDToolbox
"""
def __init__(self, filename='POSCAR', disp_ion=0.005, disp_lattice=0.000):
"""
Initializes the class from the original structure file and displacement amplitudes
"""
self.filename = filename
self.disp_ion = disp_ion
self.disp_lattice = disp_lattice
if os.path.isfile(filename) == False:
sys.exit('Correct path to a structure POSCAR/cif file must be provided')
self.structure = Structure.from_file(self.filename)
print(self.structure)
# dictionary with ionic displacements
self.structures_ion = {}
if self.disp_ion > 0.0:
for name, structure_displaced in move_all_atoms(self.structure, self.disp_ion):
self.structures_ion[name] = structure_displaced
else:
print("Ionic displacement is zero. Only the reference structure is returned.\n")
# dictionary with lattice displacements
self.structures_lattice = {}
if self.disp_lattice > 0.0:
for name, structure_displaced in move_all_lattice(self.structure, self.disp_lattice):
self.structures_lattice[name] = structure_displaced
else:
print("Lattice displacement is zero. Strain contribution won't be computed.\n")
def generate_scf(self, user_incar_custom):
"""
Generate folders with calculations: INCAR, POSCAR, POTCAR, KPOINTS
"""
user_incar={"ALGO":"Normal","EDIFF":5e-8,"LWAVE":False,"LVHAR":False,"LAECHG":False,"NPAR":4,"ICHARG":2}
if len(self.structures_ion) > 0:
generate_scf_folders(self.structures_ion, {**user_incar, **user_incar_custom})
if len(self.structures_lattice) > 0:
generate_scf_folders(self.structures_lattice, {**user_incar, **user_incar_custom})
def check_scf(self):
"""
Check either all scf calculations have been completed correctly
"""
calcs_failed_ion = []
if len(self.structures_ion) > 0:
calcs_failed_ion = check_files(self.structures_ion, 'CHGCAR')
calcs_failed_lattice = []
if len(self.structures_lattice) > 0:
calcs_failed_lattice = check_files(self.structures_lattice, 'CHGCAR')
calcs_failed = calcs_failed_ion + calcs_failed_lattice
if len(calcs_failed) == 0:
return(True)
else:
print('Following calculations have problems: ', calcs_failed)
return(False)
def generate_old_polarization(self):
"""
Generate folders with (old-type) polarization calculations for each direction
"""
if len(self.structures_ion) > 0:
generate_old_polarization_folders(self.structures_ion)
if len(self.structures_lattice) > 0:
generate_old_polarization_folders(self.structures_lattice)
def generate_new_polarization(self):
"""
Generate folders with (new-type) polarization calculations
"""
if len(self.structures_ion) > 0:
generate_new_polarization_folders(self.structures_ion)
if len(self.structures_lattice) > 0:
generate_new_polarization_folders(self.structures_lattice)
def generate_nscf_soc(self, saxis, user_incar_custom):
"""
Generate folders with non self-consistent calculations with spin-orbit coupling
"""
user_incar={"ICHARG":11, "ALGO":"Normal", "EDIFF":5e-8, "NELMDL":15, "LCHARG":False, "LWAVE":False, "LVHAR":False, "LAECHG":False, "NPAR":2, "LREAL":True, "ISIF": 2}#, "ISYM":-1}
if len(self.structures_ion) > 0:
generate_nscf_soc_folders(self.structures_ion, saxis, {**user_incar, **user_incar_custom})
if len(self.structures_lattice) > 0:
generate_nscf_soc_folders(self.structures_lattice, saxis, {**user_incar, **user_incar_custom})