├── README.md └── third_order_fc_tdep.py /README.md: -------------------------------------------------------------------------------- 1 | # extract-thirdorder-forceconstant 2 | extract thirdorder force constants from TDEP output 3 | 4 | POSCAR and thirorder forceconstants files are needed 5 | -------------------------------------------------------------------------------- /third_order_fc_tdep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Fri Jun 12 15:53:16 2020 5 | 6 | """ 7 | 8 | import numpy as np 9 | import numpy.linalg as lg 10 | import os 11 | import matplotlib.pyplot as plt 12 | import matplotlib 13 | 14 | font = {'family' : 'Times','size' : 16} 15 | 16 | matplotlib.rc('font', **font) 17 | 18 | def read_fc3(path): 19 | try: 20 | file = os.path.join(path,'outfile.forceconstant_thirdorder') 21 | with open(file) as fc3: 22 | fc3_raw = fc3.readlines() 23 | except FileNotFoundError as notexist: 24 | print('File do no exist {}'.format(notexist)) 25 | finally: 26 | return fc3_raw 27 | 28 | 29 | def read_poscar(path): 30 | fract = [] 31 | try: 32 | file = os.path.join(path,'POSCAR') 33 | with open(file) as poscar: 34 | poscar = poscar.readlines() 35 | a = poscar[2]; 36 | b = poscar[3]; 37 | c = poscar[4]; 38 | abc =np.asarray(a.strip('/n').split(), dtype= float), np.asarray(b.strip('/n').split(), dtype= float), np.asarray(c.strip('/n').split(), dtype= float) 39 | total_atoms = np.array(poscar[6].strip('/n').split(), dtype= int).sum() 40 | for item in range(8,8+total_atoms): 41 | fract.append(np.array(poscar[item].strip('/n').split(), dtype= float)) 42 | return abc, fract 43 | 44 | except FileNotFoundError as notexist: 45 | print('File do no exist {}'.format(notexist)) 46 | 47 | 48 | def fc3_atom(start,fc3_raw,fract): 49 | triples = int(fc3_raw[start+1].strip('\n').split()[0]) 50 | end = start+1+triples*15; 51 | #print(f"triples {triples} for atom, end {end} index") 52 | 53 | x_posi = fc3_raw[start+2:start+2+triples*15:15]; 54 | y_posi = fc3_raw[start+3:start+3+triples*15:15]; 55 | z_posi = fc3_raw[start+4:start+4+triples*15:15]; 56 | # atoms positions (triples index, abc axis, xyz in abc axis) 57 | atom_positions = np.zeros((triples,3,3)) 58 | 59 | x_idx = start+8; 60 | y_idx = start+9; 61 | z_idx = start+10; 62 | 63 | triples_x = fc3_raw[x_idx:x_idx+triples*15:15] 64 | triples_y = fc3_raw[y_idx:y_idx+triples*15:15] 65 | triples_z = fc3_raw[z_idx:z_idx+triples*15:15] 66 | atom = np.zeros((triples,3,3)) 67 | for i in range(triples): 68 | atom[i,0,:] = np.asarray(triples_x[i].strip('\n').split(),dtype = float); 69 | atom[i,1,:] = np.asarray(triples_y[i].strip('\n').split(),dtype = float); 70 | atom[i,2,:] = np.asarray(triples_z[i].strip('\n').split(),dtype = float); 71 | atom_positions[i,0,:] = fract[np.asarray(x_posi[i].strip('\n').split()[0],dtype = int)-1] 72 | atom_positions[i,1,:] = fract[np.asarray(y_posi[i].strip('\n').split()[0],dtype = int)-1] 73 | atom_positions[i,2,:] = fract[np.asarray(z_posi[i].strip('\n').split()[0],dtype = int)-1] 74 | return atom, end, atom_positions 75 | 76 | def fc3_all_atoms(fc3_raw,fract): 77 | start = 1; 78 | atoms = [] 79 | positions = [] 80 | while (start < len(fc3_raw)-1): 81 | each_atom,each_end,each_position= fc3_atom(start,fc3_raw,fract) 82 | atoms.append(each_atom) 83 | positions.append(each_position) 84 | start = each_end; 85 | return atoms, positions 86 | 87 | def normfc3_all_atoms(atoms_fc3,abc,positions_fc3): 88 | atoms_num = len(atoms_fc3) 89 | normfc3 = [] 90 | distancefc3= [] 91 | for atom in range(atoms_num): 92 | each_distance = [] 93 | each_fc3=[] 94 | for item in range(len(atoms_fc3[atom])): 95 | each_fc3.append(lg.norm(atoms_fc3[atom][item])) 96 | dist1 = np.matmul(np.transpose(abc),positions_fc3[atom][item][1]-positions_fc3[atom][item][0]) 97 | dist2 = np.matmul(np.transpose(abc),positions_fc3[atom][item][2]-positions_fc3[atom][item][0]) 98 | #each_distance.append(min(lg.norm(dist1),lg.norm(dist2))) 99 | each_distance.append(lg.norm(dist1)) 100 | #each_distance.append(lg.norm(dist1)+lg.norm(dist2)) 101 | #print(f"index {item} of triple and fc {lg.norm(atoms_fc3[0][item])}"); 102 | normfc3.append(each_fc3) 103 | distancefc3.append(each_distance) 104 | return normfc3, distancefc3 105 | 106 | def normfc3_plot(atoms,normfc3,distancefc3,path,alpha=0.8): 107 | #atoms = len(normfc3) 108 | fig, ax = plt.subplots(figsize=(10,8)) 109 | for atom in range(atoms): 110 | ax.plot(distancefc3[atom],np.asarray(normfc3[atom]),'o',label = f"atom {atom}",alpha =alpha) 111 | ax.legend(shadow = None, frameon = False,fancybox = None) 112 | ax.set_xlim([0.5,5]) 113 | ax.set_ylim([0,60]) 114 | ax.set_xlabel('Triple distance (A)') 115 | ax.set_ylabel('Norm of third order forceconstant (eV/A^3)') 116 | fig.savefig(path+'/fc3.png',dpi=150) 117 | 118 | 119 | 120 | r_path = #path 121 | fc3_raw=read_fc3(r_path) 122 | # lattice constant 123 | abc,fract= read_poscar(r_path) 124 | atoms_fc3, positions_fc3 = fc3_all_atoms(fc3_raw,fract) 125 | normfc3_r,distancefc3_r = normfc3_all_atoms(atoms_fc3,abc,positions_fc3) 126 | #normfc3_plot(6,normfc3_r,distancefc3_r,r_path) 127 | 128 | 129 | 130 | m1_path = # path 131 | fc3_raw=read_fc3(m1_path) 132 | # lattice constant 133 | abc,fract= read_poscar(m1_path) 134 | atoms_fc3, positions_fc3 = fc3_all_atoms(fc3_raw,fract) 135 | normfc3_m1,distancefc3_m1 = normfc3_all_atoms(atoms_fc3,abc,positions_fc3) 136 | #normfc3_plot(12,normfc3_m1,distancefc3_m1,m1_path) 137 | 138 | 139 | fc_m1 = np.loadtxt(#path) 140 | fc_r = np.loadtxt(#path) 141 | fig, ax = plt.subplots(figsize=(8,5)) 142 | ax.plot(fc_m1[:,1],fc_m1[:,2],'o',label = "M1",color = 'blue') 143 | ax.plot(fc_r[:,1],fc_r[:,2],'o',label = "Rutile",color = 'red') 144 | ax.legend(shadow = None, frameon = False,fancybox = None) 145 | ax.set_xlim([1,5]) 146 | ax.set_ylim([0,12]) 147 | ax.set_xlabel(r'Pair distance $(A)$') 148 | ax.set_ylabel(r'Norm of second order forceconstant $(eV/A^{2})$') 149 | fig.savefig(m1_path+'/fc2_R_M1.png',dpi=150) 150 | 151 | 152 | fig, ax = plt.subplots(figsize=(8,5)) 153 | for atom in range(2): 154 | ax.plot(distancefc3_r[atom],np.asarray(normfc3_r[atom]),'o',color='red',alpha =0.8) 155 | for atom in range(2): 156 | ax.plot(distancefc3_m1[atom],np.asarray(normfc3_m1[atom]),'o',color='blue',alpha =0.8) 157 | 158 | ax.legend(shadow = None, frameon = False,fancybox = None) 159 | ax.set_xlim([1,5]) 160 | ax.set_ylim([0,60]) 161 | ax.set_xlabel(r'Triple distance $(A)$') 162 | ax.set_ylabel(r'Norm of third order forceconstant $(eV/A^{3})$') 163 | fig.savefig(m1_path+'/fc3.png',dpi=150) 164 | 165 | 166 | #ax.legend(shadow = None, frameon = False,fancybox = None) 167 | ax.set_xlim([1,5]) 168 | ax.set_ylim([0,60]) 169 | ax.set_xlabel(r'Triple distance $(A)$') 170 | ax.set_ylabel(r'Norm of third order forceconstant $(eV/A^{3})$') 171 | #fig.savefig(m1_path+'/fc3.png',dpi=150) 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | --------------------------------------------------------------------------------