Source code for dpti.lib.vasp
#!/usr/bin/python3
import numpy as np
[docs]
def regulate_poscar(poscar_in, poscar_out):
with open(poscar_in) as fp:
lines = fp.read().split("\n")
names = lines[5].split()
counts = [int(ii) for ii in lines[6].split()]
assert len(names) == len(counts)
uniq_name = []
for ii in names:
if ii not in uniq_name:
uniq_name.append(ii)
uniq_count = np.zeros(len(uniq_name), dtype=int)
for nn, cc in zip(names, counts):
uniq_count[uniq_name.index(nn)] += cc
natoms = np.sum(uniq_count)
posis = lines[8 : 8 + natoms]
all_lines = []
for ele in uniq_name:
ele_lines = []
for ii in posis:
ele_name = ii.split()[-1]
if ele_name == ele:
ele_lines.append(ii)
all_lines += ele_lines
all_lines.append("")
ret = lines[0:5]
ret.append(" ".join(uniq_name))
ret.append(" ".join([str(ii) for ii in uniq_count]))
ret.append("Direct")
ret += all_lines
with open(poscar_out, "w") as fp:
fp.write("\n".join(ret))
[docs]
def sort_poscar(poscar_in, poscar_out, new_names):
with open(poscar_in) as fp:
lines = fp.read().split("\n")
names = lines[5].split()
counts = [int(ii) for ii in lines[6].split()]
new_counts = np.zeros(len(counts), dtype=int)
for nn, cc in zip(names, counts):
new_counts[new_names.index(nn)] += cc
natoms = np.sum(new_counts)
posis = lines[8 : 8 + natoms]
all_lines = []
for ele in new_names:
ele_lines = []
for ii in posis:
ele_name = ii.split()[-1]
if ele_name == ele:
ele_lines.append(ii)
all_lines += ele_lines
all_lines.append("")
ret = lines[0:5]
ret.append(" ".join(new_names))
ret.append(" ".join([str(ii) for ii in new_counts]))
ret.append("Direct")
ret += all_lines
with open(poscar_out, "w") as fp:
fp.write("\n".join(ret))
[docs]
def perturb_xz(poscar_in, poscar_out, pert=0.01):
with open(poscar_in) as fp:
lines = fp.read().split("\n")
zz = lines[4]
az = [float(ii) for ii in zz.split()]
az[0] += pert
zz = [str(ii) for ii in az]
zz = " ".join(zz)
lines[4] = zz
with open(poscar_out, "w") as fp:
fp.write("\n".join(lines))
[docs]
def reciprocal_box(box):
rbox = np.linalg.inv(box)
rbox = rbox.T
# rbox = rbox / np.linalg.det(box)
# print(np.matmul(box, rbox.T))
# print(rbox)
return rbox
def _poscar_natoms(lines):
numb_atoms = 0
for ii in lines[6].split():
numb_atoms += int(ii)
return numb_atoms
def _poscar_scale_direct(str_in, scale):
lines = str_in.copy()
numb_atoms = _poscar_natoms(lines)
pscale = float(lines[1])
pscale = pscale * scale
lines[1] = str(pscale) + "\n"
return lines
def _poscar_scale_cartesian(str_in, scale):
lines = str_in.copy()
numb_atoms = _poscar_natoms(lines)
# scale box
for ii in range(2, 5):
boxl = lines[ii].split()
boxv = [float(ii) for ii in boxl]
boxv = np.array(boxv) * scale
lines[ii] = f"{boxv[0]:.16e} {boxv[1]:.16e} {boxv[2]:.16e}\n"
# scale coord
for ii in range(8, 8 + numb_atoms):
cl = lines[ii].split()
cv = [float(ii) for ii in cl]
cv = np.array(cv) * scale
lines[ii] = f"{cv[0]:.16e} {cv[1]:.16e} {cv[2]:.16e}\n"
return lines
[docs]
def poscar_natoms(poscar_in):
with open(poscar_in) as fin:
lines = list(fin)
return _poscar_natoms(lines)
[docs]
def poscar_scale(poscar_in, poscar_out, scale):
with open(poscar_in) as fin:
lines = list(fin)
if "D" == lines[7][0] or "d" == lines[7][0]:
lines = _poscar_scale_direct(lines, scale)
elif "C" == lines[7][0] or "c" == lines[7][0]:
lines = _poscar_scale_cartesian(lines, scale)
else:
raise RuntimeError(f"Unknow poscar coord style at line 7: {lines[7]}")
with open(poscar_out, "w") as fout:
fout.write("".join(lines))
[docs]
def poscar_vol(poscar_in):
with open(poscar_in) as fin:
lines = list(fin)
box = []
for ii in range(2, 5):
words = lines[ii].split()
vec = [float(jj) for jj in words]
box.append(vec)
scale = float(lines[1].split()[0])
box = np.array(box)
box *= scale
return np.linalg.det(box)