def test_110(self): axes = np.array([[ 1, 1, 0], [-1, 1, 0], [ 0, 0, 1]]) uaxes = np.array([[ 2.**0.5/2., 2.**0.5/2., 0], [-2.**0.5/2., 2.**0.5/2., 0], [ 0, 0, 1.0]]) assert np.allclose(axes_check(axes), uaxes)
def test_not_orthogonal(self): axes = np.array([[ 1, 1, 0], [ 1,-3, 0], [ 0, 0, 1]]) with pytest.raises(ValueError): axes_check(axes)
def test_left_handed(self): axes = np.array([[ 1, 1, 0], [ 1,-1, 0], [ 0, 0, 1]]) with pytest.raises(ValueError): axes_check(axes)
def test_bad_shape(self): with pytest.raises(AssertionError): axes_check([[12,124], [124,62], [1234, 124]])
def test_parallel(self): assert np.allclose(axes_check(5*np.eye(3)), np.eye(3))
def nye(system, p, neighbor_list=None, neighbor_list_cutoff=None, axes=None, tmax = 27): axes = system.prop('axes') nlist = system.prop('nlist') natoms = system.natoms() T,vmag = axes_check(axes) if len(p) == 1: p = p[0] else: raise ValueError('Multiple unique sites not supported yet') p = p.dot(np.transpose(T)) #Change tmax=angle to tmax=cos(angle) tmax = np.cos(tmax * np.pi / 180) iden = np.identity(3) eps = np.array([[[ 0, 0, 0],[ 0, 0, 1],[ 0,-1, 0]], [[ 0, 0,-1],[ 0, 0, 0],[ 1, 0, 0]], [[ 0, 1, 0],[-1, 0, 0],[ 0, 0, 0]]]) #Set r1 to smallest interatomic distance from p r1 = 50. for pi in p: if r1 > mag(pi): r1 = mag(pi) #Identify largest number of nearest neighbors nmax = 0 for ns in nlist: if ns[0] > nmax: nmax=ns[0] #Initialize variables (done here to reduce memory allocations making it slightly faster) q = np.zeros((nmax, 3)) temp = [-1 for y in xrange(nmax)] P = np.zeros((nmax, 3)) Q = np.zeros((nmax, 3)) G = [[] for y in xrange(natoms)] nye = np.zeros((3, 3)) gradG = np.zeros((3, 3, 3)) #Loop to calculate correspondence tensor, G, and strain data for i in xrange(natoms): #Reset temp list used to identify p-q pairs for t in xrange(len(temp)): temp[t] = -1 #Calculate radial neighbor vectors, q, and associate to perfect crystal vectors, p using theta. #Only match p-q if cos(angle) between them is largest and greater than tmax. for n in xrange(nlist[i][0]): j = nlist[i][n+1] q[n] = system.dvect(i, j) theta = tmax for s in xrange(len(p)): if (p[s].dot(q[n]) / (mag(p[s]) * mag(q[n])) > theta): temp[n] = s theta = p[s].dot(q[n]) / (mag(p[s]) * mag(q[n])) #Check if the particular p has already been assigned to another q #Remove the p-q pair that is farther from r1 if temp[n] >=0: for k in xrange(n): if temp[n] == temp[k]: nrad = abs(r1 - mag(q[n])) krad = abs(r1 - mag(q[k])) if nrad < krad: temp[k]=-1 else: temp[n]=-1 #Construct reduced P, Q matrices from p-q pairs c = 0 for n in xrange(nlist[i][0]): if temp[n] >= 0: Q[c] = q[n] P[c] = p[temp[n]] c+=1 #Compute lattice correspondence tensor, G, from P and Q if c == 0: G[i] = iden print i+1 raise ValueError('An atom lacks pair sets. Check neighbor list') else: G[i], resid, rank, s = np.linalg.lstsq(Q[:c], P[:c]) #Compute strain properties strain = ((iden - G[i]) + (iden - G[i]).T) / 2. inv1 = strain[0,0] + strain[1,1] + strain[2,2] inv2 = (strain[0,0] * strain[1,1] + strain[0,0] * strain[2,2] + strain[1,1] * strain[2,2] - strain[0,1]**2 - strain[0,2]**2 - strain[1,2]**2) rot = ((iden - G[i]) - (iden - G[i]).T) / 2. ang_vel = (rot[0,1]**2 + rot[0,2]**2 + rot[1,2]**2)**0.5 system.atoms(i, 'strain', strain) system.atoms(i, 'strain_invariant_1', inv1) system.atoms(i, 'strain_invariant_2', inv2) system.atoms(i, 'angular_velocity', ang_vel) #Construct the gradient tensor of G, gradG for i in xrange(natoms): for x in xrange(3): for y in xrange(3): Q = np.zeros((nlist[i][0], 3)) dG = np.zeros((nlist[i][0])) for n in xrange(nlist[i][0]): j = nlist[i][n+1] Q[n] = system.dvect(i, j) dG[n] = G[j][x,y] - G[i][x,y] gradG[x, y], resid, rank, s = np.linalg.lstsq(Q, dG) #Use gradG to build the nye tensor, nye for ij in xrange(3): nye[0,ij] = -gradG[2, ij, 1] + gradG[1, ij, 2] nye[1,ij] = -gradG[0, ij, 2] + gradG[2, ij, 0] nye[2,ij] = -gradG[1, ij, 0] + gradG[0, ij, 1] system.atoms(i, 'Nye', nye)
def solve(self, C, burgers, axes=None, tol=1e-8): """Performs the Stroh method to obtain solution terms p, A, L, and k. Required Arguments: C -- an instance of ElasticConstants. b -- a numpy array representing the Burgers vector. Keyword Arguments: axes -- rotational axes of the system. If given, then C and b will be transformed. tol -- tolerance parameter used to round off near-zero values. """ burgers = np.asarray(burgers, dtype='float64') if axes is not None: T = axes_check(axes) burgers = T.dot(burgers) C = C.transform(axes) Cijkl = C.Cijkl m = np.array([1.0, 0.0, 0.0]) n = np.array([0.0, 1.0, 0.0]) #Matrixes of Cijkl constants used to construct N mm = np.einsum('i,ijkl,l', m, Cijkl, m) mn = np.einsum('i,ijkl,l', m, Cijkl, n) nm = np.einsum('i,ijkl,l', n, Cijkl, m) nn = np.einsum('i,ijkl,l', n, Cijkl, n) #The four 3x3 matrixes that represent the quadrants of N NB = -np.linalg.inv(nn) NA = NB.dot(nm) NC = mn.dot(NA) + mm ND = mn.dot(NB) #N is the 6x6 array, where the eigenvalues are the roots p #and the eigenvectors give A and L N = np.array(np.vstack((np.hstack((NA, NB)), np.hstack((NC, ND))))) #Calculate the eigenvectors and eigenvalues eig = np.linalg.eig(N) p = eig[0] eigvec = np.transpose(eig[1]) #separate the eigenvectors into A and L A = np.array([eigvec[0,:3], eigvec[1,:3], eigvec[2,:3], eigvec[3,:3], eigvec[4,:3], eigvec[5,:3]]) L = np.array([eigvec[0,3:], eigvec[1,3:], eigvec[2,3:], eigvec[3,3:], eigvec[4,3:], eigvec[5,3:]]) #calculate k k = 1. / (2. * np.einsum('si,si->s', A, L)) #Calculation verification checks try: assert np.allclose(np.einsum('s,si,sj->ij', k,A,L), np.identity(3, dtype='complex128'), atol=tol) assert np.allclose(np.einsum('s,si,sj->ij', k,A,A), np.zeros((3,3), dtype='complex128'), atol=tol) assert np.allclose(np.einsum('s,si,sj->ij', k,L,L), np.zeros((3,3), dtype='complex128'), atol=tol) assert np.allclose(np.einsum('s,t,si,ti->st', k**.5,k**.5,A,L) + np.einsum('s,t,ti,si->st', k**.5,k**.5,A,L), np.identity(6, dtype='complex128'), atol = tol) except: raise ValueError('Stroh checks failed!') #assign property values self.__burgers = burgers self.__Cijkl = Cijkl self.__tol = tol self.__p = p self.__A = A self.__L = L self.__k = k self.__m = m self.__n = n