def GetPrimLattice(latt, pos, num, dictp): is_prim = None rot = np.identity(3) tr = SymTrans(rot, dictp, num, pos, latt) #print('tr:\n', tr) if tr is not None: if len(tr) == 1: print('Input cell is primitive!') is_prim = 1 # // primitive cell flag #print('primitive lattice:\n', latt) # // delaunay of primitive lattice vec #print('primitive numbers:\n', num) #print('primitive cell positions:\n', pos) # atom postion #return latt, num, pos #// delaunay change part flag, reduc_b, delauP = delaunay.Delaunay(latt, -1) if flag: new_pos = delaunay.ChangeOfBasis(pos, np.linalg.inv(delauP)) print('primitive lattice (delaunay):\n', reduc_b) # // delaunay of primitive lattice vec print('primitive cell positions:\n', [list(i) for i in new_pos]) # atom postion return reduc_b, num, new_pos, is_prim else: print('Input cell is not primitive! Changing...') is_prim = 0 # // convetional cell flag ori_tr = [ np.array([1.000000000, 0.0000000000, 0.0000000000]), np.array([0.000000000, 1.0000000000, 0.0000000000]), np.array([0.000000000, 0.0000000000, 1.0000000000]) ] #print('original:\n', ori_tr) prim_vec = tr[1:] + ori_tr # delete the first vec in tr (ori-ori) print('all primitive translations:\n', prim_vec) #min_prim_latt = np.zeros((3, 3)) flag3, min_prim_latt = check_volume1( prim_vec, latt) # // delaunay of primitive lattice vec if flag3 == 'Found': #print('final primitive lattice\n', min_prim_latt) #prim_latt, new_num, new_pos = AtomPosConv2Prim(min_prim_latt, latt, pos, num) #return prim_latt, new_num, new_pos #print('new numbers:\n', new_num) #print('new positions:\n', new_pos) # // delaunay change part flag, reduc_b, delaup = delaunay.Delaunay(min_prim_latt, -1) if flag: print('primitive lattice (delaunay):\n', reduc_b) reduc_latt, new_num, new_pos = AtomPosConv2Prim( reduc_b, latt, pos, num) print('primitive cell positions:\n', [list(i) for i in new_pos]) # atom postion return reduc_latt, new_num, new_pos, is_prim
def GetStandardPos(std_latt, pos, num, trans_matrix, center, is_prim, origin, prim_flag=False): # Get standard positions tp_positions = [] positions = [] std_num = [] std_pos = [] if is_prim: tp1_positions = delaunay.ChangeOfBasis(pos, np.linalg.inv(trans_matrix)) tp = np.zeros(3) for i in tp1_positions: tp_positions.append(np.array(i) + origin) # // Xc~ = Q * Xp + Pc shift = [[0, 0, 0]] if center == 'A_FACE': shift.append([0, 0.5, 0.5]) elif center == 'B_FACE': shift.append([0.5, 0, 0.5]) elif center == 'C_FACE': shift.append([0.5, 0.5, 0]) elif center == 'BODY': shift.append([0.5, 0.5, 0.5]) elif center == 'R_CENTER': shift.append([2. / 3, 1. / 3, 1. / 3]) shift.append([1. / 3, 2. / 3, 2. / 3]) elif center == 'FACE': shift.append([0, 0.5, 0.5]) shift.append([0.5, 0, 0.5]) shift.append([0.5, 0.5, 0]) # new_pos = np.zeros(3) for j in range(len(tp_positions)): for i in range(len(shift)): new_pos = np.array(tp_positions[j]) + np.array(shift[i]) tp2 = new_pos.copy() for k in range(3): if tp2[k] < 0.0: tp2[k] = int(tp2[k] - 0.5) else: tp2[k] = int(tp2[k] + 0.5) new_pos = new_pos - tp2 for k in range(3): if new_pos[k] < 0.0: new_pos[k] += 1.0 positions.append(new_pos) # // Xc = Xc~ + shift vec # print('cek1', positions) for j in num: for i in range(len(shift)): std_num.append(j) # adjust positions to list format for i in positions: tp = [] for j in i: tp.append(j) std_pos.append(tp) else: # input is conventional tp_positions = delaunay.ChangeOfBasis(pos, np.linalg.inv(trans_matrix)) for i in tp_positions: positions.append(np.array(i) + origin) # adjust positions to list format for i in positions: tp = [] for j in i: tp.append(j) std_pos.append(tp) std_num = num.copy() # print('cek1', positions) if is_prim or prim_flag: print('standard conventional lattice:\n', std_latt) print('standard conventional numbers:\n', std_num) print('standard conventional positions:\n', std_pos) return StandardPrimCell(std_latt, std_pos, std_num, center) else: return std_latt, std_num, std_pos
def AtomPosPrim2Conv(prim_latt, latt, pos, num, cel_size): latt_vol = np.linalg.det(latt) prim_vol = np.linalg.det(prim_latt) ratio = latt_vol / prim_vol print('ratio1:\n', ratio) #cel_size = len(pos) ratio = np.around(ratio, decimals=3) ratio = abs(ratio) print('ratio2:\n', ratio) inv_tp_vec = np.linalg.inv(latt) P = np.transpose(np.dot(prim_latt, inv_tp_vec)) # P, Q is a vertical vec Q = np.linalg.inv(P) print('check Q1: ', np.linalg.det(Q)) deterQ = np.around(np.linalg.det(Q), decimals=3) print('check Q2: ', deterQ) if abs( deterQ ) != ratio: # P: big(conv) --> small(prim). so P is no larger than 1, Q is no smaller than 1 print('Error1') return None, None, None if (cel_size / ratio) * ratio != cel_size: print('Error2') return None, None, None tp_new_pos = delaunay.ChangeOfBasis(pos, Q) #print('temp_postion1:\n', tp_new_pos) new_site = [] tolerance = 0.00001 for i in range(cel_size): new_site.append( i ) # // note: maybe index is out of range if it isn't intialized with len(cel_size) for cnt in range(100): for i in range(cel_size): for j in range(cel_size): if num[i] == num[j]: if VecIsOverlap(np.array(tp_new_pos[i]), np.array(tp_new_pos[j]), prim_latt, tolerance): if new_site[j] == j: new_site[ i] = j # // change the equiv to the first showed one break #print('new site:\n', new_site) new_num = [] for i in set(new_site): new_num.append(num[i]) # // ['Zr', 'O', 'O'] print('check!', new_num) tp_p = [] for i in new_site: tp_p.append( tp_new_pos[i] ) # // atom sites according to the new_site ['Zr', 'O', 'O'] #print('temp_postion2:\n', tp_p) # // boundary trim new_posi = [] for i in range(cel_size): new_posi.append(np.zeros(3)) for i in range(cel_size): for j in range(3): if abs(tp_new_pos[i][j] - tp_p[i][j]) > 0.5: if tp_new_pos[i][j] < tp_p[i][j]: new_posi[new_site[i]][j] += tp_new_pos[i][j] + 1 else: new_posi[new_site[i]][j] += tp_new_pos[i][j] - 1 else: new_posi[new_site[i]][j] = tp_new_pos[i][j] # // average of the overlapped two atoms ave_pos = cel_size / len(new_posi) for j in range(len(new_posi)): #tp2 = np.zeros(3) for k in range(3): new_posi[j][k] = new_posi[j][k] / ave_pos tp2 = new_posi[j].copy( ) # // Watch out! Don't use "tp2 = new_posi[j]", otherwise they will change at the same time for k in range(3): if tp2[k] < 0.0: tp2[k] = int(tp2[k] - 0.5) else: tp2[k] = int(tp2[k] + 0.5) new_posi[j] = new_posi[j] - tp2 for k in range(3): if new_posi[j][k] < 0.0: new_posi[j][k] += 1.0 new_pos = [] for i in set(new_site): new_pos.append(new_posi[i]) print('new numbers:\n', new_num) print('new positions:\n', [list(i) for i in new_pos]) return prim_latt, new_num, new_pos
def AtomPosConv2Prim(prim_latt, latt, pos, num): """ Conventional lattice changes to primitive lattice Find correspoing new atomic positions (for primitive) """ latt_vol = np.linalg.det(latt) prim_vol = np.linalg.det(prim_latt) ratio = latt_vol / prim_vol cel_size1 = len(pos) if ratio < 0.0: ratio = int(ratio - 0.5) else: ratio = int(ratio + 0.5) ratio = abs(ratio) #print('ratio2:\n', ratio) inv_tp_vec = np.linalg.inv(latt) P = np.transpose(np.dot(prim_latt, inv_tp_vec)) # P, Q : vertical vectors Q = np.linalg.inv(P) # print('check Q1: ', np.linalg.det(Q)) for i in range(3): for j in range(3): if Q[i, j] < 0.0: Q[i, j] = int(Q[i, j] - 0.5) else: Q[i, j] = int(Q[i, j] + 0.5) # print('check Q2: ', np.linalg.det(Q)) # P: big(conv) --> small(prim) # P is no larger than 1, but Q is no smaller than 1 if abs(np.linalg.det(Q)) != ratio: print('Error1') return None, None, None if (cel_size1 / ratio) * ratio != cel_size1: print('Error2') return None, None, None tp_new_pos = delaunay.ChangeOfBasis(pos, Q) #print('temp_postion1:\n', tp_new_pos) new_site = [] tolerance = 0.00001 # note: index maybe out of range if it isn't initialized with len(cel_size) for i in range(cel_size1): new_site.append(i) for cnt in range(100): for i in range(cel_size1): for j in range(cel_size1): if num[i] == num[j]: if VecIsOverlap(np.array(tp_new_pos[i]), np.array(tp_new_pos[j]), prim_latt, tolerance): # change the equivalent to the first showed one if new_site[j] == j: new_site[i] = j break # print('new site:\n', new_site) new_num = [] for i in sorted(set(new_site)): new_num.append(num[i]) # test: ['Zr', 'O', 'O'] # print('check!', new_num) tp_p = [] for i in new_site: tp_p.append( tp_new_pos[i] ) # test: atomic sites according to the new_site ['Zr', 'O', 'O'] # boundary trim new_posi = [] for i in range(cel_size1): new_posi.append(np.zeros(3)) for i in range(cel_size1): for j in range(3): if abs(tp_new_pos[i][j] - tp_p[i][j]) > 0.5: if tp_new_pos[i][j] < tp_p[i][j]: new_posi[new_site[i]][j] += tp_new_pos[i][j] + 1 else: new_posi[new_site[i]][j] += tp_new_pos[i][j] - 1 else: new_posi[new_site[i]][j] = tp_new_pos[i][j] # average of the overlapped two atoms ave_pos = cel_size1 / len(new_posi) for j in range(len(new_posi)): #tp2 = np.zeros(3) for k in range(3): new_posi[j][k] = new_posi[j][k] / ave_pos # Note: Don't use "tp2 = new_posi[j]" (change at the same time) tp2 = new_posi[j].copy() for k in range(3): if tp2[k] < 0.0: tp2[k] = int(tp2[k] - 0.5) else: tp2[k] = int(tp2[k] + 0.5) new_posi[j] = new_posi[j] - tp2 for k in range(3): if new_posi[j][k] < 0.0: new_posi[j][k] += 1.0 new_pos = [] for i in sorted(set(new_site)): new_pos.append(new_posi[i]) print('new numbers:\n', new_num) print('new positions:\n', [list(i) for i in new_pos]) return prim_latt, new_num, new_pos