Idpp method for creating initial NEB path =========== IDPP method is introduced by Hannes Jónsson in his paper "Improved initial guess for minimum energy path calculations" :: #!/usr/bin/python #lipai@mail.ustc.edu.cn import numpy as np import os import time step_init=0.0001 images=input("input num of images: ") ininame=raw_input("ini structure: ") finname=raw_input("fin structure: ") #read ini structure fileopen=open(ininame,'r') ini_data=fileopen.readlines() head=ini_data[:9] atom_num=sum(map(int,head[6].split())) ini_data=ini_data[9:9+atom_num] tmp=[] fix=[] for i in range(atom_num): tmp.append(map(float,ini_data[i].split()[0:3])) if(ini_data[i].split()[4]=='F'): fix.append(1) else: fix.append(0) pos_a=np.array(tmp) #read fin stucture fileopen=open(finname,'r') fin_data=fileopen.readlines() fin_data=fin_data[9:9+atom_num] tmp=[] for i in fin_data: tmp.append(map(float,i.split()[0:3])) pos_b=np.array(tmp) #correction of periodic boundary condition for i in range(atom_num): for j in range(3): if(pos_a[i][j]-pos_b[i][j]>0.5): pos_a[i][j]-=1 if(pos_a[i][j]-pos_b[i][j]<-0.5): pos_b[i][j]-=1 #get dist matrix and linear interpolation dist_a=np.zeros([atom_num,atom_num]) dist_b=np.zeros([atom_num,atom_num]) for i in range(atom_num): for j in range(atom_num): tmp_a=0 tmp_b=0 for k in range(3): tmp_a+=(pos_a[i][k]-pos_a[j][k])**2 tmp_b+=(pos_b[i][k]-pos_b[j][k])**2 dist_a[i,j]=np.sqrt(tmp_a) dist_b[i,j]=np.sqrt(tmp_b) dist_im=np.zeros([images,atom_num,atom_num]) pos_im=np.zeros([images,atom_num,3]) for i in range(images): dist_im[i]=dist_a+(i+1.0)*(dist_b-dist_a)/(images+1.0) pos_im[i]=pos_a+(i+1.0)*(pos_b-pos_a)/(images+1.0) #optimization using steepest descent method pos_tmp=np.zeros([atom_num,3]) dist_tmp=np.zeros([atom_num,atom_num]) s0=np.zeros(images) s1=np.zeros(images) flag=np.zeros(images) for im in range(images): if(flag[im]==1): continue step=step_init print "generate image "+str(im+1) loop=0 while(1): for i in range(atom_num): #get dist_tmp for j in range(atom_num): if(i==j): dist_tmp[i,j]=10 else: tmp=0 for k in range(3): tmp+=(pos_im[im][i][k]-pos_im[im][j][k])**2 dist_tmp[i,j]=np.sqrt(tmp) for i in range(atom_num): for sigma in range(3): grad=0 for j in range(atom_num): if(j!=i): grad+=2*(dist_im[im][i][j]-dist_tmp[i][j])*(pos_im[im][i][sigma]-pos_im[im][j][sigma])\ *(2*dist_im[im][i][j]-dist_tmp[i][j])/dist_tmp[i,j]**5 pos_tmp[i][sigma]=pos_im[im][i][sigma]+step*grad pos_im[im]=pos_tmp #judge convergence s0[im]=s1[im] s1[im]=0 for i in range(atom_num): for j in range(i): s1[im]+=(dist_im[im][i][j]-dist_tmp[i][j])**2/dist_tmp[i][j]**4 loop+=1 print "loop:%d"%loop if(abs(s0[im]-s1[im])<0.01): print "Converged!" flag[im]=1 break if(loop>1 and s1[im]>s0[im]): step=step/3 #mkdir and generate poscar files if(images+1<10): num='0'+str(images+1) else: num=str(images+1) os.system("mkdir 00") os.system("cp p1 00/POSCAR") os.system("mkdir "+num) os.system("cp p2 "+num+"/POSCAR") for i in range(images): if(i+1<10): num='0'+str(i+1) else: num=str(i+1) os.system("mkdir "+num) data=pos_im[i].tolist() filename=num+"/POSCAR" f=file(filename,"a+") f.writelines(head) for j in range(atom_num): line=map(str,data[j]) line=" ".join(line) if(fix[j]==1): line=line+' F F F\n' else: line=line+' T T T\n' f.write(line) f.close()