-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathIO_vasp.py
More file actions
224 lines (177 loc) · 7.41 KB
/
Copy pathIO_vasp.py
File metadata and controls
224 lines (177 loc) · 7.41 KB
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import numpy as np
from collections import namedtuple
def grid_from_POSCAR(s):
"""
Read atom cooredinates from a VASP POSCAR/CONTCAR file.
** This function assumes the coordinates are in Direct coordinates
Parameters
----------
s : string containing the data from a VASP POSCAR file
Returns
-------
grid : list of [atom index,region,m-coord,n-coord,t-coord,basis]
for each atom in the geometry
** coordinates are scaled out by a factor of a0 !!
"""
atominfo = namedtuple('atom',['ind','reg','m','n','t','basis'])
## read in lines from input file and ignore blank lines and comment lines
lines = [line.rstrip() for line in s.splitlines() if line.rstrip() if line[0] != '#']
## lattice constant
# a0 = float(lines[1].split()[0])
## supercell vectors
m = lines[2].split()
m_mag = np.linalg.norm([float(m[0]),float(m[1]),float(m[2])])
n = lines[3].split()
n_mag = np.linalg.norm([float(n[0]),float(n[1]),float(n[2])])
t = lines[4].split()
t_mag = np.linalg.norm([float(t[0]),float(t[1]),float(t[2])])
## number of atoms
## the line position in the POSCAR file may vary
## so I'm just finding the next line with a number instead of a string
## I can't guarantee that it's 100% foolproof though...
for i,line in enumerate(lines[5:]):
if line.split()[0].isdigit():
num_atoms = [int(entry) for entry in line.split()]
tot_atoms = sum(num_atoms)
continue
if line.split()[0] == 'Direct':
break
## atom positions, assumed to be in Direct coordinates
grid = []
for line in lines[5+i+1:5+i+1+tot_atoms]:
entries = line.split()
basis = 0
## assign basis atom type based on atom type defined in POSCAR?
# for cumsum in np.cumsum(num_atoms):
# if len(grid) >= cumsum: basis += 1
grid.append(atominfo(int(len(grid)),0,float(entries[0])*m_mag,float(entries[1])*n_mag,float(entries[2])*t_mag,basis))
return grid
#def grid_from_OUTCAR(s):
#
# """
# Read from a string containing the data from a VASP OUTCAR file.
# ** This old version only reads the data from the first iteration it finds
#
# Parameters
# ----------
# s : string containing the data from a VASP OUTCAR file
#
# Returns
# -------
# grid : list of [atom index,region,x-coord,y-coord,z-coord,basis]
# for each atom in the geometry
# forces : list of [force_x,force_y,force_z]
#
# """
#
# atominfo = namedtuple('atom',['ind','reg','m','n','t','basis'])
# forceinfo = namedtuple('force',['m','n','t'])
#
# for i,line in enumerate(s.splitlines()):
# if line.rstrip():
# if line.split()[0] == 'POSITION':
# break
#
# grid = []
# forces = []
# for line in s.splitlines()[i+2:]:
# if line.split()[0][0] == '-':
# break
# else:
# entries = line.split()
# grid.append(atominfo(int(len(grid)),0,float(entries[0]),float(entries[1]),float(entries[2]),0))
# forces.append(forceinfo(float(entries[3]),float(entries[4]),float(entries[5])))
#
# return grid,forces
def grid_from_OUTCAR(s):
"""
Read from a string containing the data from a VASP POSCAR file.
Parameters
----------
s : string containing the data from a VASP POSCAR file
Returns
-------
grid : list of [atom index,region,x-coord,y-coord,z-coord,basis]
for each atom in the geometry
for each iteration in the OUTCAR
forces : list of [force_x,force_y,force_z]
for each iteration in the OUTCAR
"""
atominfo = namedtuple('atom',['ind','reg','m','n','t','basis'])
forceinfo = namedtuple('force',['m','n','t'])
grid = []
forces = []
for i,line in enumerate(s.splitlines()[:]):
if line.rstrip():
## find the start of "POSITION" data for each iteration
if line.split()[0] == 'POSITION':
grid.append([])
forces.append([])
## start reading data, which starts 2 lines after
for line in s.splitlines()[i+2:]:
if line.split()[0][0] == '-':
## dashed line indicates end of this set of data
break
else:
entries = line.split()
grid[-1].append(atominfo(int(len(grid[-1])),0,float(entries[0]),float(entries[1]),float(entries[2]),0))
forces[-1].append(forceinfo(float(entries[3]),float(entries[4]),float(entries[5])))
return grid,forces
def write_LGFCAR(G,mapping,size_1,size_12,size_123,header):
"""
Write a string containing the data for a VASP LGFCAR file.
Parameters
----------
G : LGF matrix (numpy array of shape (size_123,size_2))
mapping : list, in which mapping[LGF_index] = DFT_index
size_1 : number of atoms in reg 1
size_12 : number of atoms in reg 1+2
size_123 : number of atoms in reg 1+2+3
header : comment string
Returns
-------
s : string containing the data for a VASP LGFCAR file
"""
size_2 = size_12-size_1
## create string which will be written to LGFCAR file
s = header + '\n'
## this next line must be:
## <min DFT index reg 2> <max DFT index reg 2> <min DFT index reg 1> <max DFT index reg 3> <total # entries>
s += '%d %d %d %d %d\n'%(int(min(mapping[size_1:size_12])),int(max(mapping[size_1:size_12])),
1,size_123,size_2*size_123)
## determine the order to output LGF entries
indexlist = []
for j in range(size_2):
for i in range(size_123):
## [DFT atom index j, DFT atom index i, LGF row index i, LGF col index j]
indexlist.append([mapping[j+size_1],mapping[i],i,j])
## sort indexlist based on DFT atom index j first, then DFT atom index i
indexlist = sorted(indexlist)
for DFTj,DFTi,row,col in indexlist:
## <DFT atom index j> <DFT atom index i> <Gxx> <Gxy> <Gxz> <Gyx> <Gyy> <Gyz> <Gzx> <Gzy> <Gzz>
Gij = G[row*3:(row+1)*3,col*3:(col+1)*3]
s += '%d %d %.12f %.12f %.12f %.12f %.12f %.12f %.12f %.12f %.12f\n'%(int(DFTj),int(DFTi),
Gij[0,0],Gij[0,1],Gij[0,2],Gij[1,0],Gij[1,1],Gij[1,2],Gij[2,0],Gij[2,1],Gij[2,2])
return s
def map_indices(grid_123,elements):
"""
Map atom indices used in calculating LGF to atom indices in VASP
Parameters
----------
grid_123 : list of [atom index,region,m-coord,n-coord,t-coord,basis]
for each atom in regions 1-3 of geometry
elements : list of element indices corresponding to each basis atom
Returns
-------
mapping_LGFtoDFT : list, in which mapping[LGF_index] = DFT_index
"""
temp = [[atom.ind,elements[atom.basis]] for atom in grid_123]
## resort temp list by element type
## mapping[DFT_index-1] = lGF_index
mapping_DFTtoLGF = np.array(sorted(temp,key=lambda temp:temp[1]))[:,0]
mapping_LGFtoDFT = mapping_DFTtoLGF.copy()
## mapping[LGF_index] = DFT_index
## LGF indexing starts from 0; DFT indexing starts from 1
for DFTind,LGFind in enumerate(mapping_DFTtoLGF):
mapping_LGFtoDFT[LGFind] = int(DFTind+1)
return mapping_LGFtoDFT