Skip to content

Instantly share code, notes, and snippets.

@Asif-Iqbal-Bhatti
Last active July 6, 2022 03:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Asif-Iqbal-Bhatti/ee37c6bd98e567cce59be257256171f1 to your computer and use it in GitHub Desktop.
Save Asif-Iqbal-Bhatti/ee37c6bd98e567cce59be257256171f1 to your computer and use it in GitHub Desktop.
CODE to extract various properties from VASP output files
#!/usr/bin/env python3
'''
#####---------------------------------------------------------
#####---------------------------------------------------------
# Credit : Asif Iqbal BHATTI
# CODE to: OBTAIN Elastic properties form OUTCAR files,
# compare POSCAR and CONTCAR volume deformation
# upon minimization, and extract energy from a number
# of directories.
# VERSION: This script runs with python3 or later
# FORMAT : POSCAR VASP5 format
# DATE : 28/12/2019
# USAGE : python3 sys.argv[0]
#####---------------------------------------------------------
#####---------------------------------------------------------
'''
import os, sys, spglib, scipy
import math, glob
import numpy as np
import subprocess
from os import listdir
from os.path import isfile, join
from pathlib import Path
from termcolor import colored
import multiprocessing as mp
from colorama import Fore, Back, Style, init
from pylab import *
init(autoreset=True)
'''
##########################---------------------------------------------------------
# 1- Reading only POSCAR file from the command prompt in a given directory
##########################---------------------------------------------------------
'''
def poscar():
if not os.path.exists('POSCAR'):
print (' ERROR: POSCAR does not exist here.')
sys.exit(0)
print('Reading POSCAR/CONTCAR: \n')
pos = []; kk = []; lattice = []; sum = 0
file = open('POSCAR','r') or open('CONTCAR','r')
firstline = file.readline() # IGNORE first line comment
secondfline = file.readline() # scale
Latvec1 = file.readline()
#print ("Lattice vector 1:", (Latvec1), end = '')
Latvec2 = file.readline()
#print ("Lattice vector 2:", (Latvec2), end = '')
Latvec3 = file.readline()
#print ("Lattice vector 3:", (Latvec3), end = '')
elementtype=file.readline().split()
if (str.isdigit(elementtype[0])):
sys.exit("VASP 4.X POSCAR detected. Please add the atom types")
print ("Types of elements:", str(elementtype), end = '\n')
numberofatoms=file.readline()
Coordtype=file.readline()
print ("Coordtype:", (Coordtype), end = '\n')
########################---------------------------------------------------------
print (">>>>>>>>>-------------------# of Atoms--------------------")
nat = numberofatoms.split()
nat = [int(i) for i in nat]
print (nat)
for i in nat:
sum = sum + i
numberofatoms = sum
print ("Number of atoms:", (numberofatoms), end = '\n')
########################---------------------------------------------------------
#print (">>>>>>>>>---------------Atomic positions------------------")
for x in range(int(numberofatoms)):
coord = file.readline().split()
coord = [float(i) for i in coord]
pos = pos + [coord]
pos = np.array(pos)
#print (pos)
file.close()
########################---------------------------------------------------------
a=[]; b=[]; c=[];
Latvec1=Latvec1.split()
Latvec2=Latvec2.split()
Latvec3=Latvec3.split()
for ai in Latvec1:
a.append(float(ai))
for bi in Latvec2:
b.append(float(bi))
for ci in Latvec3:
c.append(float(ci))
########################---------------------------------------------------------
print (">>>>>>>>>---------------Lattice vectors distortions-----------------")
lattice = np.array([a] + [b] + [c])
#determinant = np.linalg.det(lattice)
lld = local_lattice_distortion(a,b,c)
print ("lattice distortion parameter g: {}".format(lld) )
print (">>>>>>>>>---------------Space group-----------------")
print (" ")
sp, symm = space_group_analyse(lattice, pos)
print ( sp, symm )
print (" ")
print (">>>>>>>>>--------------------------------------------")
print ('a=', a)
print ('b=', b)
print ('c=', c)
gamma = math.degrees(math.acos(np.dot(a,b) / (np.linalg.norm(a) * np.linalg.norm(b))))
alpha = math.degrees(math.acos(np.dot(b,c) / (np.linalg.norm(b) * np.linalg.norm(c))))
beta = math.degrees(math.acos(np.dot(a,c) / (np.linalg.norm(a) * np.linalg.norm(c))))
print ("ratio c/a = %2f" %(np.linalg.norm(c) / np.linalg.norm(a) ))
print ("-"*100)
print ('||a||=%2f, \u03B1= %2f' %(np.linalg.norm(a), alpha))
print ('||b||=%2f \u03B2= %2f' %(np.linalg.norm(b), beta))
print ('||c||=%2f \u03B3= %2f' %(np.linalg.norm(c), gamma))
print ('Vol= %4.8f A^3; %4.8f [a.u]^3' %(volume(a,b,c,math.radians(alpha),math.radians(beta),math.radians(gamma) )))
###
def local_lattice_distortion(a1,b1,c1):
#print ("The lattice distortion in paracrystals is measured by the lattice distortion parameter g")
#print (Back.YELLOW + "Wang, S. Atomic structure modeling of multi-principal-element alloys by the principle")
#print (Back.YELLOW + "of maximum entropy. Entropy 15, 5536–5548 (2013).")
#print ("")
a=np.linalg.norm(a1); b=np.linalg.norm(b1); c=np.linalg.norm(c1)
d = np.array([a,b,c])
d_mean = np.mean(d); d_std = np.std(d)
d_square_mean = (a**2 + b**2 + c**2)/3
g = np.sqrt( d_square_mean/(d_mean)**2 - 1 )
return g
###
def space_group_analyse(lattice, pos):
numbers = [1,2]
cell = (lattice, pos, numbers)
sp=spglib.get_spacegroup(cell, symprec=1e-5)
symm=spglib.get_symmetry(cell, symprec=1e-5)
#print(spglib.niggli_reduce(lattice, eps=1e-5))
#mesh = [8, 8, 8]
#mapping, grid = spglib.get_ir_reciprocal_mesh(mesh, cell, is_shift=[0, 0, 0])
## All k-points and mapping to ir-grid points
#for i, (ir_gp_id, gp) in enumerate(zip(mapping, grid)):
# print("%3d ->%3d %s" % (i, ir_gp_id, gp.astype(float) / mesh))
#
## Irreducible k-points
#print("Number of ir-kpoints: %d" % len(np.unique(mapping)))
#print(grid[np.unique(mapping)] / np.array(mesh, dtype=float))
#
##
## With shift
##
#mapping, grid = spglib.get_ir_reciprocal_mesh(mesh, cell, is_shift=[1, 1, 1])
#
## All k-points and mapping to ir-grid points
#for i, (ir_gp_id, gp) in enumerate(zip(mapping, grid)):
# print("%3d ->%3d %s" % (i, ir_gp_id, (gp + [0.5, 0.5, 0.5]) / mesh))
#
## Irreducible k-points
#print("Number of ir-kpoints: %d" % len(np.unique(mapping)))
#print((grid[np.unique(mapping)] + [0.5, 0.5, 0.5]) / mesh)
return sp, symm
###
def poscar_VASP42VASP5():
if not os.path.exists('POSCAR' and 'POTCAR'):
print (' ERROR: POSCAR does not exist here.')
sys.exit(0)
file1 = open("POSCAR",'r')
line1 = file1.readlines()
file1.close()
file2 = open("POTCAR",'r')
line2 = file2.readlines()
file2.close()
atom_number=[]
for i in line1:
if ("Direct" or "direct" or "d" or "D") in i:
PP=line1.index(i)
atom_number = line1[5].split()
print(atom_number)
elementtype=[]; count=0
for i in line2:
if ("VRHFIN") in i:
count+=1
#print (i.split('=')[1].split(':')[0])
elementtype.append(i.split('=')[1].split(':')[0])
test = open("POSCAR_W",'w')
for i in range(5):
test.write( line1[i] )
for j in elementtype:
test.write("\t" + j)
test.write("\n" )
for j in atom_number:
test.write("\t" + j )
test.write("\n" )
test.write("Selective dynamics")
test.write("\n" )
for i in range(len(line1)-PP):
test.write(line1[PP+i] )
test.close()
print (" File is converted: POSCAR_W")
###
'''
#####---------------------------------------------------------
# 2- Looping over all directories containing POSCAR & CONTCAR files
#####---------------------------------------------------------
'''
def main_poscar():
count = 0
os.system("rm out_POSCARS.dat")
VOL_P = []; pos = []; kk = []; lattice = [];
mypath = os.getcwd()
print ("-"*100)
print (Back.YELLOW + "{:15s} {:15s} {:15.6s} {:15.6s} {:15.6s} {:15.15s}".format("Directory", "# of atoms", "||a||", \
"||b||", "||c||", "VOL_POS[A^3]"),end="\n" )
print ("-"*100)
for entry in os.listdir(mypath):
if os.path.isdir(os.path.join(mypath, entry)):
#print (entry)
for file in os.listdir(entry):
if file == "POSCAR":
count+=1; sum = 0
filepath = os.path.join(entry, file)
#f = open(filepath, 'r')
#print (f.read())
#f.close()
fo = open(filepath, 'r')
ofile=open('out_POSCARS.dat','a')
#print (colored('>>>>>>>> Name of the file: ','red'), fo.name, end = '\n', flush=True)
ofile.write (fo.name + '\n')
ofile.write ("")
firstline = fo.readline()
secondfline = fo.readline()
Latvec1 = fo.readline()
#print ("Lattice vector 1:", (Latvec1), end = '')
#ofile.write (Latvec1)
Latvec2 = fo.readline()
#print ("Lattice vector 2:", (Latvec2), end = '')
#ofile.write (Latvec2)
Latvec3 = fo.readline()
#print ("Lattice vector 3:", (Latvec3), end = '')
#ofile.write (Latvec3)
elementtype=fo.readline()
elementtype = elementtype.split()
#print ("Types of elements:", str(elementtype), end = '')
#ofile.write (str(elementtype))
numberofatoms=fo.readline()
#print ("Number of atoms:", (numberofatoms), end = '')
#ofile.write ((numberofatoms))
Coordtype=fo.readline()
##########################---------------------------------------------------------
#print ("**********-------------------# of Atoms--------------------")
nat = numberofatoms.split()
nat = [int(i) for i in nat]
for i in nat:
sum = sum + i
numberofatoms = sum
#print ("{} :: Number of atoms: {}".format(nat, numberofatoms) )
##########################---------------------------------------------------------
#print ("-----------------------Atomic positions-----------------")
#print ("Coordtype:", (Coordtype), end = '')
for x in range(int(numberofatoms)):
coord = fo.readline().split()
coord = [float(i) for i in coord]
pos = pos + [coord]
pos = np.array(pos)
#print (pos)
ofile.write ("\n")
fo.close()
##########################---------------------------------------------------------
a=[]; b=[]; c=[];
Latvec1=Latvec1.split()
Latvec2=Latvec2.split()
Latvec3=Latvec3.split()
##########################---------------------------------------------------------
for ai in Latvec1: a.append(float(ai))
for bi in Latvec2: b.append(float(bi))
for ci in Latvec3: c.append(float(ci))
#print ('a=', a)
ofile.write ("'a=' {}\n".format(a))
#print ('b=', b)
ofile.write ("'b=' {}\n".format(b))
#print ('c=', c)
ofile.write ("'c=' {}\n".format(c))
lld = local_lattice_distortion(a,b,c)
##########################---------------------------------------------------------
alpha, beta, gamma = lattice_angles(a,b,c)
VOL_POS = np.dot(a, np.cross(b,c))
VOL_P.append(VOL_POS)
ofile.write ("'\u03B1=' {} '\u03B2=' {} '\u03B3=' {}\n".format(alpha,beta,gamma))
ofile.write ("'||a||=' {}\n".format(np.linalg.norm(a)))
ofile.write ("'||b||=' {}\n".format(np.linalg.norm(b)))
ofile.write ("'||c||=' {}\n".format(np.linalg.norm(c)))
#print ("#####------------------------------------------------")
#print ("a={} \t ||a||={:10.6f}".format(a, np.linalg.norm(a)) )
#print ("b={} \t ||b||={:10.6f}".format(b, np.linalg.norm(b)) )
#print ("c={} \t ||c||={:10.6f}".format(c, np.linalg.norm(c)) )
print ("{:15s} {:6d} {:15.6f} {:15.6f} {:15.6f} {:15.6f}".format(fo.name, numberofatoms, np.linalg.norm(a), \
np.linalg.norm(b), np.linalg.norm(c), VOL_POS) )
print ("'\u03B1=' {:6.6f} '\u03B2=' {:6.6f} '\u03B3=' {:6.6f} g={:6.6f}".format(alpha,beta,gamma,lld))
print ("."*5)
#print ('Vol= {:6.6f} A^3'.format(VOL_POS))
ofile.write ("***************************************************\n")
ofile.close()
print ("_"*30)
print ("Number of folders detected: ", count)
return VOL_P
####
def main_contcar():
count = 0
os.system("rm out_CONTCARS.dat")
VOL_C = []; pos = []; kk = []; lattice = []; sum = 0
mypath = os.getcwd()
print ("-"*100)
print (Back.GREEN + "{:15s} {:15s} {:15.6s} {:15.6s} {:15.6s} {:15.15s}".format("Directory", "# of atoms", "||a||", \
"||b||", "||c||", "VOL_CON[A^3]"),end="\n" )
print ("-"*100)
print(Style.RESET_ALL)
for entry in os.listdir(mypath):
if os.path.isdir(os.path.join(mypath, entry)):
for file in os.listdir(entry):
if file == "CONTCAR":
count+=1; sum = 0
filepath = os.path.join(entry, file)
fo = open(filepath, 'r')
ofile=open('out_CONTCARS.dat','a')
#print (colored('>>>>>>>> Name of the file: ','yellow'), fo.name, end = '\n', flush=True)
ofile.write (fo.name + '\n')
ofile.write ("")
firstline = fo.readline()
secondfline = fo.readline()
Latvec1 = fo.readline()
Latvec2 = fo.readline()
Latvec3 = fo.readline()
elementtype=fo.readline()
elementtype = elementtype.split()
numberofatoms=fo.readline()
Coordtype=fo.readline()
#print ("Coordtype:", (Coordtype), end = '')
##########################---------------------------------------------------------
#print ("**********-------------------# of Atoms--------------------")
nat = numberofatoms.split()
nat = [int(i) for i in nat]
for i in nat:
sum = sum + i
numberofatoms = sum
#print ("{} :: Number of atoms: {}".format(nat, numberofatoms) )
##########################---------------------------------------------------------
#print ("//////---------------Atomic positions-----------------")
for x in range(int(numberofatoms)):
coord = fo.readline().split()
coord = [float(i) for i in coord]
pos = pos + [coord]
pos = np.array(pos)
#print (pos)
ofile.write ("\n")
fo.close()
##########################---------------------------------------------------------
a=[]; b=[]; c=[];
Latvec1=Latvec1.split()
Latvec2=Latvec2.split()
Latvec3=Latvec3.split()
##########################---------------------------------------------------------
for ai in Latvec1: a.append(float(ai))
for bi in Latvec2: b.append(float(bi))
for ci in Latvec3: c.append(float(ci))
#print ('a=', a)
ofile.write ("'a=' {}\n".format(a))
#print ('b=', b)
ofile.write ("'b=' {}\n".format(b))
#print ('c=', c)
ofile.write ("'c=' {}\n".format(c))
lld = local_lattice_distortion(a,b,c)
##########################---------------------------------------------------------
alpha, beta, gamma = lattice_angles(a,b,c)
VOL_CON = np.dot(a, np.cross(b,c))
VOL_C.append(VOL_CON)
ofile.write ("'\u03B1=' {} '\u03B2=' {} '\u03B3=' {}\n".format(alpha,beta,gamma))
ofile.write ("'||a||=' {}\n".format(np.linalg.norm(a)))
ofile.write ("'||b||=' {}\n".format(np.linalg.norm(b)))
ofile.write ("'||c||=' {}\n".format(np.linalg.norm(c)))
#print ("-"*80)
#print ("a={} \t ||a||={:10.6f}".format(a, np.linalg.norm(a)) )
#print ("b={} \t ||b||={:10.6f}".format(b, np.linalg.norm(b)) )
#print ("c={} \t ||c||={:10.6f}".format(c, np.linalg.norm(c)) )
print ("{:15s} {:6d} {:15.6f} {:15.6f} {:15.6f} {:15.6f}".format(fo.name, numberofatoms, np.linalg.norm(a), \
np.linalg.norm(b), np.linalg.norm(c), VOL_CON) )
print ("'\u03B1=' {:6.6f} '\u03B2=' {:6.6f} '\u03B3=' {:6.6f} g={:6.6f}".format(alpha,beta,gamma,lld))
print ("."*5)
#print ('Vol= {:6.6f} A^3'.format(VOL_CON), end="\n")
ofile.write ("***************************************************\n")
ofile.close()
#print (VOL_C)
print ("-"*80)
print ("Number of folders detected: ", count)
return VOL_C
#### math.sin function takes argument in radians ONLY
def volume(a,b,c,alpha,beta,gamma):
ang2atomic = 1.889725988579 # 1 A = 1.889725988579 [a.u]
Ang32Bohr3 = 6.74833304162 # 1 A^3 = 6.7483330371 [a.u]^3
length = np.linalg.norm(a) * np.linalg.norm(b) * np.linalg.norm(c)
volume = length * ( np.sqrt(1 + 2 * math.cos(alpha) * math.cos(beta) * math.cos(gamma) - math.cos(alpha)**2 - math.cos(beta)**2 - math.cos(gamma)**2) )
vol_au = volume * Ang32Bohr3
return volume, vol_au
#### Ordering of returning angles variables does matter
def lattice_angles(a,b,c):
### gamma = Cos-1( (a.b)/||a||.||b|| )
### alpha = Cos-1( (b.c)/||b||.||c|| )
### beta = Cos-1( (a.c)/||a||.||c|| )
gamma = math.degrees(math.acos(np.dot(a,b) / (np.linalg.norm(a) * np.linalg.norm(b))))
alpha = math.degrees(math.acos(np.dot(b,c) / (np.linalg.norm(b) * np.linalg.norm(c))))
beta = math.degrees(math.acos(np.dot(a,c) / (np.linalg.norm(a) * np.linalg.norm(c))))
return alpha, beta, gamma
####### BASH way of finding the # of directories in a working directory ###
def volume_diff(VOL_P, VOL_C):
n=os.popen("find . -mindepth 1 -maxdepth 1 -type d | wc -l").read()
print ("-"*80)
print ("VOL Diff A^3 %18s %12s %15.15s" %("CONTCAR", "POSCAR", "contcar-poscar"))
print ("-"*80)
for i in range(int(n)):
print ("The difference is: %12.6f %12.6f %15.8f " %(VOL_C[i], VOL_P[i], VOL_C[i] - VOL_P[i]) )
####
'''
#####---------------------------------------------------------
# 3- ELASTIC PROPERTIES from VASP OUTCAR file "STRESS APPROACH"
#####---------------------------------------------------------
'''
class Elastic_Matrix:
def print_Cij_Matrix(): ###EXERCISE
Bij = []; C = "C"
for i in range(0, 6, 1):
Bij.append([])
for j in range(1,7, 1):
Bij[i].append((C + str(i+1) + str(j)))
l = np.matrix(Bij)
return l
def langragian_strain():
kk = ('x', 'y', 'z'); C = "E"; Eij=[]
eta = {
"xx" : 11,
"yy" : 22,
"zz" : 33,
"yz" : 23,
"xz" : 13,
"xy" : 12 }
print ( "The Langragian strain in Voigt notation: ")
print ( eta.items())
for n in kk:
for m in kk:
Eij.append( (C + str(n) + str(m)) )
ls = np.matrix(Eij).reshape(3,3)
return ls
def elastic_matrix_VASP_STRESS():
while True:
if not os.path.exists('OUTCAR'):
print (' ERROR: OUTCAR does not exist here.')
sys.exit(0)
s=np.zeros((6,6))
c=np.zeros((6,6))
file = open("OUTCAR",'r')
lines = file.readlines()
file.close()
for i in lines:
if "TOTAL ELASTIC MODULI (kBar)" in i:
ll=lines.index(i)
if "LATTYP" in i:
crystaltype=str(i.split()[3])
print ("DETECTED CRYSTAL FROM OUTCAR:", crystaltype)
print (" ")
for i in range(0,6):
l=lines[ll+3+i] # indexing a line in huge file
word = l.split()
s[i][:] = word[1:7]
for j in range(0,6):
c[i][j] = float(s[i][j])/10.0
##########-------------------stress tensor------------------
Cij = np.matrix(c)
np.set_printoptions(precision=4, suppress=True)
print (Cij)
print(Elastic_Matrix.print_Cij_Matrix() )
print(Elastic_Matrix.langragian_strain() )
print ("\nEigen Values of the matrix Cij:")
evals = np.linalg.eigvals(Cij)
if evals.all() > 0:
print(evals)
print("All Eigen values are positive")
##########-------------------Compliance tensor------------------
##########------------------- s_{ij} = C_{ij}^{-1}
Sij = np.linalg.inv(Cij)
#---------------------------- ELASTIC PROPERTIES -----------------------------------
stability_test(Cij, crystaltype)
#------------------------------- Voigt bulk modulus K_v $(GPa)$---------------
#------------------ 9K_v = (C_{11}+C_{22}+C_{33}) + 2(C_{12} + C_{23} + C_{31})
Kv = ((Cij[0,0] + Cij[1,1] + Cij[2,2]) + 2 * (Cij[0,1] + Cij[1,2] + Cij[2,0]))/9.0
#------------------------------- Reuss shear modulus G_v $(GPa)$------------------
#------------------ 15/G_R = 4(s_{11}+s_{22}+s_{33}) - 4(s_{12} + s_{23} + s_{31}) + 3(s_{44} + s_{55} + s_{66})$
Gv = ((Cij[0,0] + Cij[1,1] + Cij[2,2]) - (Cij[0,1] + Cij[1,2] + Cij[2,0]) + 3 * (Cij[3,3] + Cij[4,4] + Cij[5,5]))/15.0
#------------------------------- Reuss bulk modulus K_r $(GPa)$----------------
#------------------ 1/K_R = (s_{11}+s_{22}+s_{33}) + 2(s_{12} + s_{23} + s_{31})$
Kr = 1/((Sij[0,0] + Sij[1,1] + Sij[2,2]) + 2 * (Sij[0,1] + Sij[1,2] + Sij[2,0]) )
#------------------------------- Reuss shear modulus G_r $(GPa)$------------------
Gr = 15/(4 * (Sij[0,0] + Sij[1,1] + Sij[2,2]) - 4 * (Sij[0,1] + Sij[1,2] + Sij[2,0]) + 3 * (Sij[3,3] + Sij[4,4] + Sij[5,5]))
#-----------------------------------------------------------------------------------
## Young's Modulus "E": Voigt
Ev = (9*Kv*Gv)/(3*Kv + Gv)
## Young's: Reuss
Er = (9*Kr*Gr)/(3*Kr + Gr)
## Poisson's ratio: Voigt
Nu_V = (3*Kv - Ev)/(6*Kv)
## Poisson's ratio: Reuss
Nu_R = (3*Kr - Er)/(6*Kr)
## P-wave modulus, M: Voigt
MV = Kv + (4*Gv/3.0)
## P-wave modulus, M: Reuss
MR = Kr + (4*Gr/3.0)
#-----------------------------------------------------------------------------------
#-------------- Voigt-Reuss-Hill Approximation: average of both methods
Kvrh = (Kv + Kr)/2.0
Gvrh = (Gv + Gr)/2.0
Mvrh = (MV + MR)/2.0
Evrh = (Ev + Er)/2.0
Nu_vrh = (Nu_V + Nu_R)/2.0
KG_ratio_V = Kv/Gv
KG_ratio_R = Kr/Gr
KG_ratio_vrh = Kvrh/Gvrh
#-------------- Isotropic Poisson ratio $\mu
#-------------- $\mu = (3K_{vrh} - 2G_{vrh})/(6K_{vrh} + 2G_{vrh})$
mu = (3 * Kvrh - 2 * Gvrh) / (6 * Kvrh + 2 * Gvrh )
#----------------------------------------------------------------------
#-----------------------------------------------------------------------------------
print ("\n \n Voigt Reuss Average")
print ("-------------------------------------------------------")
print ("Bulk modulus (GPa) %9.3f %9.3f %9.3f " % (Kv, Kr, Kvrh))
print ("Shear modulus (GPa) %9.3f %9.3f %9.3f " % (Gv, Gr, Gvrh))
print ("Young modulus (GPa) %9.3f %9.3f %9.3f " % (Ev, Er, Evrh))
print ("Poisson ratio %9.3f %9.3f %9.3f " % (Nu_V, Nu_R, Nu_vrh))
print ("P-wave modulus (GPa) %9.3f %9.3f %9.3f " % (MV, MR, Mvrh))
print ("Bulk/Shear ratio %9.3f %9.3f %9.3f (%s) " %(KG_ratio_V, KG_ratio_R, KG_ratio_vrh, ductile_test(KG_ratio_vrh) ))
print ("-------------------------------------------------------")
print("Isotropic Poisson ratio: ", mu)
break
def ductile_test(ratio):
if(ratio > 1.75):
return "ductile"
else:
return "brittle"
###
def stability_test(matrix, crystaltype):
c = np.copy(matrix)
if(crystaltype =="cubic"):
print ("Cubic crystal system \n")
print ("Born stability criteria for the stability of cubic system are : \ [Ref- Mouhat and Coudert, PRB 90, 224104 (2014)] \n")
print ("(i) C11 - C12 > 0; (ii) C11 + 2C12 > 0; (iii) C44 > 0 \n ")
## check (i) keep in mind list starts with 0, so c11 is stored as c00
if(c[0][0] - c[0][1] > 0.0):
print ("Condition (i) satisfied.")
else:
print ("Condition (i) NOT satisfied.")
if(c[0][0] + 2*c[0][1] > 0.0):
print ("Condition (ii) satified.")
else:
print ("Condition (ii) NOT satisfied.")
if(c[3][3] > 0.0):
print ("Condition (iii) satified.")
else:
print ("Condition (iii) NOT satisfied.")
if(crystaltype =="hexagonal"):
print ("Hexagonal crystal system \n")
print ("Born stability criteria for the stability of hexagonal system are \: [Ref- Mouhat and Coudert, PRB 90, 224104 (2014)] \n")
print ("(i) C11 - C12 > 0; (ii) 2*C13^2 < C33(C11 + C12); (iii) C44 > 0 \n ")
## check (i) keep in mind list starts with 0, so c11 is stored as c00
if(c[0][0] - c[0][1] > 0.0):
print ("Condition (i) satisfied.")
else:
print ("Condition (i) NOT satisfied.")
if(2*(c[0][2]*c[0][2]) < c[2][2]*(c[0][0] + c[0][1])):
print ("Condition (ii) satified.")
else:
print ("Condition (ii) NOT satisfied.")
if(c[3][3] > 0.0):
print ("Condition (iii) satified.")
else:
print ("Condition (iii) NOT satisfied.")
###
def born_stability_criterion():
print ("Born stability criteria for the stability of following systems \n")
print ("Cubic crystal system.... \n")
print ("(i) C11 - C12 > 0; (ii) C11 + 2C12 > 0; (iii) C44 > 0 \n ")
print ("Hexagonal crystal system.... \n")
print ("(i) C11 - C12 > 0; (ii) 2*C13^2 < C33(C11 + C12); (iii) C44 > 0 \n ")
print ("Tetragonal crystal system.... \n")
print ("(i) C11 - C12 > 0; (ii) 2*C13^2 < C33(C11 + C12); (iii) C44 > 0; (iv) C66 > 0; (v) 2C16^2 < C66*(C11-C12) \n ")
print ("rhombohedral crystal system.... \n")
print ("(i) C11 - C12 > 0; (ii) C13^2 < (1/2)*C33(C11 + C12); (iii) C14^2 < (1/2)*C44*(C11-C12) = C44*C66; (iv) C44 > 0; \n ")
print ("orthorhombic crystal system.... \n")
print ("(i) C11 > 0; (ii) C11*C22 > C12^2; (iii) C11*C22*C33 + 2C12*C13*C23 - C11*C23^2 - C22*C13^2 - C33*C12^2 > 0; (iv) C44 > 0; (v) C55 > 0 ; (vi) C66 > 0 \n")
print ("Monoclinic crystal system.... \n")
print ("[Ref- Mouhat and Coudert, PRB 90, 224104 (2014), and Wu et al. PRB 76, 054115 (2007)] \n")
print ("(i) C11 > 0; (ii) C22 > 0; (iii) C33 > 0; (iv) C44 > 0; (v) C55 > 0 ; (vi) C66 > 0 ")
print ("(vii) [C11 + C22 + C33 + 2*(C12 + C13 + C23)] > 0; (viii) C33*C55 - C35^2 > 0; (ix) C44*C66 - C46^2 > 0; (x) C22 + C33 - 2*C23 > 0 ")
print ("(xi) C22*(C33*C55 - C35^2) + 2*C23*C25*C35 - (C23^2)*C55 - (C25^2)*C33 > 0 ")
print ("(xii) 2*[C15*C25*(C33*C12 - C13*C23) + C15*C35*(C22*C13 - C12*C23) + C25*C35*(C11*C23 - C12*C13)] - [C15*C15*(C22*C33 - C23^2) + C25*C25*(C11*C33 - C13^2) + C35*C35*(C11*C22 - C12^2)] + C55*g > 0 ")
print (" where, g = [C11*C22*C33 - C11*C23*C23 - C22*C13*C13 - C33*C12*C12 + 2*C12*C13*C23 ] " )
###
'''
#####---------------------------------------------------------
# 4- EXTRACT ENERGY & VOLUME from VASP OUTCAR file
#####---------------------------------------------------------
'''
def energy_vs_volume():
import fnmatch
mypath = os.getcwd()
os.system("rm energy-vs-volume energy-vs-strain")
eV2Hartree=0.036749309
Ang32Bohr3=6.74833304162
E=[]; dir_list=[]; count = 0; dir_E=[];
vol_cell=[]; strain_file=[]; strain_value=[] # strain_value is deformation
print (" >>>>> Extracting Energy from directories <<<<<<")
for entry in os.listdir(mypath):
if not os.path.exists('strain-01'):
print (' ERROR: strain-* does not exist here.')
sys.exit(0)
if fnmatch.fnmatchcase(entry,'strain-*'):
f = open(entry,'r')
lines = f.readline() #Read first line only
strain_value.append( float(lines) )
f.close()
if os.path.isfile(os.path.join(mypath, entry)):
strain_file.append(entry)
if os.path.isdir(os.path.join(mypath, entry)):
dir_list.append(entry)
for file in os.listdir(entry):
if file == "OUTCAR":
filepath = os.path.join(entry, file)
if not os.path.exists(filepath):
print (' ERROR: OUTCAR does not exist here.')
sys.exit(0)
f = open(filepath,'r')
lines = f.readlines()
f.close()
for i in lines:
if " free energy TOTEN =" in i:
m=float(i.split()[4])
if " volume of cell :" in i:
v=float(i.split()[4])
vol_cell.append(v)
E.append(m)
count+=1
print("# of folders detected: ", count)
print ("Directory :%10.6s %14s %18s %25.20s " % ("Folder", "Energy(eV)", "Vol_of_cell(A^3)", "strain_deformation" ))
for i in range(math.floor(count/2)): # 0 to 4
print ("Folder name: %10.10s %16.8f %16.8f %16.12s %14.4f" %(dir_list[i], E[i], vol_cell[i], strain_file[i], strain_value[i] ))
if (bool(math.floor(count/2))):
i = math.floor(count/2)
print(Back.GREEN + 'Folder name: %10.10s %16.8f %16.8f %16.12s %14.4f <--Ref' % (dir_list[i], E[i], vol_cell[i], strain_file[i], strain_value[i] ))
print(Style.RESET_ALL, end="")
for i in range(math.ceil(count/2), count, 1):
print ("Folder name: %10.10s %16.8f %16.8f %16.12s %14.4f" %(dir_list[i], E[i], vol_cell[i], strain_file[i], strain_value[i] ))
#rc = subprocess.Popen(['bash', 'extract_energy.sh'])
print (colored('ENERGIES & VOLUMES ARE WRITTEN IN ATOMIC UNITS TO A FILE <energy-vs-volume>','yellow'), end = '\n', flush=True)
print (colored('IT WILL BE READ BY ELASTIC SCRIPTS FOR POSTPROCESSING eV-->Ha; A^3-->Bohr^3','yellow'), end = '\n', flush=True)
file = open("energy-vs-volume",'w')
for i in range(count):
file.write ("%14.6f %14.6f\n" %(vol_cell[i] * Ang32Bohr3, E[i] * eV2Hartree))
file.close()
file = open("energy-vs-strain",'w')
for i in range(count):
file.write ("%12.6f %14.6f\n" %(strain_value[i], E[i] * eV2Hartree))
file.close()
###
'''
#####---------------------------------------------------------
# 5- FITTING ENERGY & VOLUME CURVE from VASP OUTCAR file
#####---------------------------------------------------------
'''
def fitting_energy_vs_volume_curve():
from sys import stdin
import matplotlib.pyplot as plt
import matplotlib.ticker as ptk
import pylab as pyl
import matplotlib.style
bohr_radius = 0.529177
bohr32ang3 = 0.14818474347
joule2hartree = 4.3597482
joule2rydberg = joule2hartree/2.
unitconv = joule2hartree/bohr_radius**3*10.**3
if (str(os.path.exists('energy-vs-volume'))=='False'):
sys.exit("ERROR: file energy-vs-volume not found!\n")
energy = []; volume = []
read_energy = open('energy-vs-volume',"r")
while True:
line = read_energy.readline()
line = line.strip()
if len(line) == 0: break
energy.append(float(line.split()[1]))
volume.append(float(line.split()[0]))
volume,energy=sortvolume(volume,energy)
print ("===============================")
print ("Lattice symmetry codes" )
print ("-------------------------------")
print ("1 --> Simple cubic (sc)" )
print ("2 --> Body-centered cubic (bcc)")
print ("3 --> Face-centered cubic (fcc)")
print ("-------------------------------")
print ("0 --> Others")
print ("===============================\n")
scheck = input("Enter lattice symmetry code [default 0] >>>> ").replace(" ", "")
'''
These factors are for the conversion from the conventional cell to primitive cell
BCC: (a^3)/2 primitive cell volume
FCC: (a^3)/4 primitive cell volume
'''
isym = 0; factor = 1
if ( scheck == "1" ): isym = 1 ; factor=1 ; slabel = "(sc) "
if ( scheck == "2" ): isym = 2 ; factor=2 ; slabel = "(bcc)"
if ( scheck == "3" ): isym = 3 ; factor=4 ; slabel = "(fcc)"
print ("Verification lattice symmetry code >>>> %d " %(isym) )
#-------------------------------------------------------------------------------
print ('%s' %('-'*105) )
print ('%20.25s %29.30s %21.30s %11.12s %18.30s' %("Opt_vol Bohr^3 (Ang^3)", "Lattice_const Bohr (A)", "Bulk_modulus [GPa]", "Log(chi)", "Polynomial_order"))
print ('%s' %('-'*105) )
for order_of_fit in range(2, 11): #order of polynomial fitting
if order_of_fit % 2 == 0:
order_of_fit = int(order_of_fit)
fitr = np.polyfit(volume,energy,order_of_fit)
curv = np.poly1d(fitr)
oned = np.poly1d(np.polyder(fitr,1)) #
bulk = np.poly1d(np.polyder(fitr,2))
bpri = np.poly1d(np.polyder(fitr,3)) #
vmin = np.roots(np.polyder(fitr))
dmin=[]
for i in range(len(vmin)):
if (abs(vmin[i].imag) < 1.e-10):
if (volume[0] <= vmin[i] and vmin[i] <= volume[-1]):
if(bulk(vmin[i]) > 0): dmin.append(vmin[i].real)
xvol = np.linspace(volume[0],volume[-1],100)
if (len(dmin) > 1): print ("WARNING: Multiple minima are found!\n")
if (len(dmin) == 0): print ("WARNING: No minimum in the given xrange!\n")
chi = 0
for i in range(len(energy)):
chi=chi+(energy[i]-curv(volume[i]))**2
chi=math.sqrt(chi)/len(energy)
#-------------------------------------------------------------------------------
for i in range(len(dmin)):
x0=dmin[len(dmin)-1-i]
v0=dmin[len(dmin)-1-i]
a0=(factor*v0)**(0.33333333333)
b0=bulk(v0)*v0*unitconv
#if (isym > 0): print ('Lattice constant = %5s %12.6f %12.6f' %(slabel,a0, a0*bohr_radius), '[Bohr, Angstrom]')
if (isym > 0):
print("%12.6f (%11.6f) %12.6f (%9.6f) %17.6f %13.2f %10d\n" %(v0, v0*bohr32ang3, a0, a0*bohr_radius, b0, math.log10(chi), order_of_fit), end="")
else:
print("%12.6f(%12.6f) %12.6f(%12.6f) %17.6f %13.2f %10d\n" %(v0, v0*bohr32ang3, a0, a0*bohr_radius, b0, math.log10(chi), order_of_fit), end="")
print ('%s' %('-'*105) )
#-------------------------------------------------------------------------------
xlabel = u'Volume [Bohr\u00B3]'; ylabel = r'Energy [Ha]'
fontlabel=20
fonttick=14
params = {'ytick.minor.size': 6,
'xtick.major.pad': 8,
'ytick.major.pad': 4,
'patch.linewidth': 2.,
'axes.linewidth': 2.,
'lines.linewidth': 1.8,
'lines.markersize': 8.0,
'axes.formatter.limits': (-4, 6)}
plt.rcParams.update(params)
plt.subplots_adjust(left=0.21, right=0.93,
bottom=0.18, top=0.88,
wspace=None, hspace=None)
yfmt = ptk.ScalarFormatter(useOffset=True,useMathText=True)
figure = plt.figure(1, figsize=(9,9))
ax = figure.add_subplot(111)
ax.text(0.5,-0.18,xlabel,size=fontlabel, transform=ax.transAxes,ha='center',va='center')
ax.text(-0.25,0.5,ylabel,size=fontlabel, transform=ax.transAxes,ha='center',va='center',rotation=90)
for line in ax.get_xticklines() + ax.get_yticklines():
line.set_markersize(6)
line.set_markeredgewidth(2)
plt.xticks(size=fonttick)
plt.yticks(size=fonttick)
pyl.grid(True)
plt.plot(xvol,curv(xvol),'b-',label='n='+str(order_of_fit)+' fit')
plt.plot(volume,energy,'go',label='calculated')
plt.plot(dmin,curv(dmin),'ro')
plt.legend(loc=9,borderaxespad=.8,numpoints=1)
ymax = max(max(curv(xvol)),max(energy))
ymin = min(min(curv(xvol)),min(energy))
dxx = abs(max(xvol)-min(xvol))/18
dyy = abs(ymax-ymin)/18
ax.yaxis.set_major_formatter(yfmt)
ax.set_xlim(min(xvol)-dxx,max(xvol)+dxx)
ax.set_ylim(ymin-dyy,ymax+dyy)
ax.xaxis.set_major_locator(MaxNLocator(7))
plt.savefig('PLOT.png',orientation='portrait',format='png')
###
def sortvolume(s,e):
ss=[]; ee=[]; ww=[]
for i in range(len(s)): ww.append(s[i])
ww.sort()
for i in range(len(s)):
ss.append(s[s.index(ww[i])])
ee.append(e[s.index(ww[i])])
return ss, ee
###
####
def Introduction():
global message
message = " ____| Python script to process various properties |____"
print(message)
####
if __name__ == "__main__":
Introduction()
print("Number of processors Detected: ", mp.cpu_count())
print(Back.MAGENTA + ' NB: POSCAR should be in VASP 5 format & without selective dynamics', end = '\n', flush=True)
print(Style.RESET_ALL)
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
print ('>>> USAGE: execute by typing python3 sys.argv[0]')
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
print ("**** Following are the options: ")
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
print ("(1) To execute ONLY POSCAR file (Lattice Matrix, lattice distortion)")
print ("(2) To find POSCAR CELL VOLUME DIFFERENCE with final CONTCAR file")
print ("(3) Extract ENERGIES from directories *")
print ("(4) Extract ELASTIC CONSTANTS from OUTCAR file (VASP: IBRION=6,ISIF=3)")
print ("(5) Fit energy vs volume curve to extract Ealstic Moduli (Exciting: Elastic code) ")
print ("(6) Convert POSCAR file from VASP4 to VASP5 format")
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
print (colored(' -----------------------------------------------------------','red'), end = '\n', flush=True)
option = input("Enter the option as listed above: ")
option = int(option)
if (option == 1):
poscar()
elif (option == 2):
VOL_P = main_poscar()
VOL_C = main_contcar()
volume_diff(VOL_P, VOL_C)
elif (option == 3):
energy_vs_volume()
elif (option == 4):
print("Reading OUTCAR. OUTCAR should be in the same directory from which this script is run ")
pool = mp.Pool(mp.cpu_count())
elastic_matrix_VASP_STRESS()
pool.close()
elif (option == 5):
fitting_energy_vs_volume_curve()
elif (option == 6):
poscar_VASP42VASP5()
else:
print ("INVALID OPTION")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment