def csl_finder_smith(r_g1tog2_g1): """ This funciton extracts the CSL basis when transformation between the two lattices is given (r_g1tog2_g1). The algorithms used are based on the following article: doi:10.1107/S056773947601231X) Parameters ---------------- r_g1tog2_g1: numpy array The 3x3 transformation matrix in g1 reference frame Returns ----------- l_csl_g1: numpy array 3 x 3 matrix with the csl basis vectors as columns Notes --------- The "Reduced" refer to the use of LLL algorithm to compute a basis that is as close to orthogonal as possible. (Refer to http://en.wikipedia.org/wiki/Lattice_reduction) for further detials on the concept of Lattice Reduction """ R_G1ToG2_G1 = np.array(r_g1tog2_g1) L_G2_G1 = R_G1ToG2_G1 # Obtain N1 and N2 N1, _ = int_man.int_mult(L_G2_G1) A = np.dot(N1, L_G2_G1) # Check that A is an integer matrix if int_man.int_check(A, 12).all(): A = np.around(A) else: raise Exception('L_G2_G1 is not a Sigma Transformation') # Smith Normal Form of A # A = U*E*V' U, E, _ = smith_nf(A) L_G1n_G1 = U # L_G1_G1n = np.linalg.inv(L_G1n_G1) # CSL Bases l_csl_g1 = csl_elem_div_thm_l1(E / N1, L_G1n_G1) if(int_man.int_check(l_csl_g1, 1e-08)).all(): l_csl_g1 = np.around(l_csl_g1) else: raise Exception('l_csl_g1 is not defined in L_G1_G1 axis') # Reduced CSL bases using the LLL algorithm l_csl_g1 = lll_reduction((l_csl_g1)) return l_csl_g1
def test_int_check(): """ Test cases for the int_check function in integer_manipulations """ b = np.array([[2, 3, 5], [6, 6.000002, -2.000001], [-0.00002, 1.5, 4]]) a = int_man.int_check(b) print(a) # ------------ b = 2.5 a = int_man.int_check(b) print(a) if __name__ == '__main__': test_int_check
def csl_finder_2d(l_pl1_g1, l_pl2_g1): """ Given two plane bases, the 2D CSL bases are obtined by utilizing the smith normal form of the transformation between the two bases Parameters --------------- l_pl1_g1, l_pl2_g1: numpy array Basis vectors of planes 1 and 2 expressed in g1 reference frame Returns --------------- l_2d_csl_g1: numpy array The basis vectors of the 2D CSL expressed in g1 reference frame """ l1 = np.array(l_pl1_g1) l2 = np.array(l_pl2_g1) # L2 = L1*T (T := T_Pl1ToPl2_Pl1) l1_linv = np.dot(np.linalg.inv(np.dot(l1.T, l1)), l1.T) t = np.dot(l1_linv, l2) # # Obtain N1 and N2 n1, a = int_man.int_mult(t) if int_man.int_check(a, 12).all: a = np.around(a) # A = U*E*V'; E is a diagonal matrix u, e, v = smith_nf(a) l2_n = np.dot(l2, np.linalg.inv(v.T)) l_2d_csl_g1 = fcd.csl_elem_div_thm_l2(e/n1, l2_n) if int_man.int_check(l_2d_csl_g1, 10).all(): l_2d_csl_g1 = np.around(l_2d_csl_g1) else: raise Exception('Wrong CSL computation') l_2d_csl_g1 = lll_reduction(l_2d_csl_g1[:, 0:2]) return l_2d_csl_g1
def check_int_mats(l1, l2): """ The function checks whether or not the elements of $A_{left}^{-1}$*B are integers Parameters ---------- l1, l2 : numpy arrays of same dimensions Returns ------- cond: numpy boolean array """ l1_linv = np.dot(np.linalg.inv(np.dot(l1.T, l1)), l1.T) cond = int_man.int_check(np.dot(l1_linv, l2), 10) return cond
def message_display(CheckMatrix, Checknumber, Message, Precis): """ This function displays a Message (passed as input) and gives and error in case the matrix passed to it is not integral.` """ cond = int_man.int_check(CheckMatrix, Precis) print( Checknumber, '.', Message, '-> ', ) txt = Col() if cond.all(): txt.c_prnt('YES', 'yel') else: txt.c_prnt('<<<Error>>>', 'amber') raise Exception('Something wrong!!')
def lll_reduction(matrix, delta=0.75): """ _________________________________________________________________________ This function has been borrowed from pymatgen project with slight changes in input and output handling. Link to the project: http://pymatgen.org/ Link to the source code: https://github.com/materialsproject/pymatgen/blob/92ee88ab6a6ec6e27b717150931e6d484d37a4e6/pymatgen/core/lattice.py _________________________________________________________________________ Performs a Lenstra-Lenstra-Lovasz lattice basis reduction to obtain a c-reduced basis. This method returns a basis which is as "good" as possible, with "good" defined by orthongonality of the lattice vectors. Args: delta (float): Reduction parameter. Default of 0.75 is usually fine. Returns: Reduced lattice. """ if int_man.int_check(matrix, 10).all(): # Transpose the lattice matrix first so that basis vectors are columns. # Makes life easier. a = np.array(matrix) sz = a.shape b = np.zeros((3, 3)) # Vectors after the Gram-Schmidt process u = np.zeros((3, 3)) # Gram-Schmidt coeffieicnts m = np.zeros(3) # These are the norm squared of each vec. b[:, 0] = a[:, 0] m[0] = np.dot(b[:, 0], b[:, 0]) for i in xrange(1, sz[1]): u[i, 0:i] = np.dot(a[:, i].T, b[:, 0:i]) / m[0:i] b[:, i] = a[:, i] - np.dot(b[:, 0:i], u[i, 0:i].T) m[i] = np.dot(b[:, i], b[:, i]) k = 2 while k <= sz[1]: # Size reduction. for i in xrange(k - 1, 0, -1): q = round(u[k - 1, i - 1]) if q != 0: # Reduce the k-th basis vector. a[:, k - 1] = a[:, k - 1] - q * a[:, i - 1] uu = list(u[i - 1, 0:(i - 1)]) uu.append(1) # Update the GS coefficients. u[k - 1, 0:i] = u[k - 1, 0:i] - q * np.array(uu) # Check the Lovasz condition. if np.dot(b[:, k - 1], b[:, k - 1]) >=\ (delta - abs(u[k - 1, k - 2]) ** 2) *\ np.dot(b[:, (k - 2)], b[:, (k - 2)]): # Increment k if the Lovasz condition holds. k += 1 else: # If the Lovasz condition fails, # swap the k-th and (k-1)-th basis vector v = a[:, k - 1].copy() a[:, k - 1] = a[:, k - 2].copy() a[:, k - 2] = v # Update the Gram-Schmidt coefficients for s in xrange(k - 1, k + 1): u[s - 1, 0:(s - 1)] = np.dot( a[:, s - 1].T, b[:, 0:(s - 1)]) / m[0:(s - 1)] b[:, s - 1] = a[:, s - 1] - np.dot(b[:, 0:(s - 1)], u[s - 1, 0:(s - 1)].T) m[s - 1] = np.dot(b[:, s - 1], b[:, s - 1]) if k > (sz[1] - 1): k -= 1 else: # We have to do p/q, so do lstsq(q.T, p.T).T instead. p = np.dot(a[:, k:sz[1]].T, b[:, (k - (sz[1] - 1)):k]) q = np.diag(m[(k - (sz[1] - 1)):k]) result = np.linalg.lstsq(q.T, p.T)[0].T u[k:sz[1], (k - (sz[1] - 1)):k] = result # checking if the reduced matrix is right handed # if np.linalg.det(a) < 0: # a[:, [1, 2]] = a[:, [2, 1]] return a else: raise Exception( 'The input to the lll_algorithm is expected to be integral')
def dsc_finder(L_G2_G1, L_G1_GO1): """ The DSC lattice is computed for the bi-crystal, if the transformation matrix l_g2_g1 is given and the basis vectors of the underlying crystal l_g_go (in the orthogonal reference go frame) are known. The following relationship is used: **The reciprocal of the coincidence site lattice of the reciprocal lattices is the DSC lattice** Parameters ---------------- l_g2_g1: numpy array transformation matrix (r_g1tog2_g1) l_g1_go1: numpy array basis vectors (as columns) of the underlying lattice expressed in the orthogonal 'go' reference frame Returns ------------ l_dsc_g1: numpy array The dsc lattice basis vectors (as columns) expressed in the g1 reference Notes --------- The "Reduced" refer to the use of LLL algorithm to compute a basis that is as close to orthogonal as possible. (Refer to http://en.wikipedia.org/wiki/Lattice_reduction) for further detials on the concept of Lattice Reduction """ L_G2_G1 = np.array(L_G2_G1) L_G1_GO1 = np.array(L_G1_GO1) L_GO1_G1 = np.linalg.inv(L_G1_GO1) # % % Reciprocal lattice of G1 # -------------------------------------------------------------- L_rG1_GO1 = reciprocal_mat(L_G1_GO1) L_GO1_rG1 = np.linalg.inv(L_rG1_GO1) # L_rG1_G1 = np.dot(L_GO1_G1, L_rG1_GO1) # % % L_G1_rG1 = L_rG1_G1^(-1); # % % Reciprocal lattice of G2 L_G2_GO1 = np.dot(L_G1_GO1, L_G2_G1) L_rG2_GO1 = reciprocal_mat(L_G2_GO1) # % % Transformation of the Reciprocal lattices # % % R_rG1TorG2_rG1 = L_rG2_G1*L_G1_rG1; L_rG2_rG1 = np.dot(L_GO1_rG1, L_rG2_GO1) Sigma_star = sigma_calc(L_rG2_rG1) # % % CSL of the reciprocal lattices L_rCSL_rG1 = csl_finder_smith(L_rG2_rG1) L_rCSL_GO1 = np.dot(L_rG1_GO1, L_rCSL_rG1) # % % Reciprocal of the CSL of the reciprocal lattices L_DSC_GO1 = reciprocal_mat(L_rCSL_GO1) L_DSC_G1 = np.dot(L_GO1_G1, L_DSC_GO1) # % % Reduction of the DSC lattice in G1 reference frame DSC_Int = int_man.int_finder(L_DSC_G1, 1e-06) t_ind = np.where(abs(DSC_Int) == abs(DSC_Int).max()) t_ind_1 = t_ind[0][0] t_ind_2 = t_ind[1][0] Mult1 = DSC_Int[t_ind_1, t_ind_2] / L_DSC_G1[t_ind_1, t_ind_2] DSC_Reduced = lll_reduction(DSC_Int) DSC_Reduced = DSC_Reduced / Mult1 L_DSC_G1 = DSC_Reduced # % % % Check this assertion: L_DSC_G1 = [Int_Matrix]/Sigma if int_man.int_check(Sigma_star*L_DSC_G1, 10).all(): L_DSC_G1 = np.around(Sigma_star*L_DSC_G1) / Sigma_star else: raise Exception('L_DSC_G1 is not equal to [Int_Matrix]/Sigma') return L_DSC_G1