def findBoundaries(self, boundDef=10): """ Find grain boundaries :param boundDef: critical misorientation :type boundDef: float """ self.buildQuatArray() print("\rFinding boundaries...", end="") syms = Quat.symEqv(self.crystalSym) numSyms = len(syms) # array to store quat components of initial and symmetric equivalents quatComps = np.empty((numSyms, 4, self.yDim, self.xDim)) # populate with initial quat components for i, row in enumerate(self.quatArray): for j, quat in enumerate(row): quatComps[0, :, i, j] = quat.quatCoef # loop of over symmetries and apply to initial quat components # (excluding first symmetry as this is the identity transformation) for i, sym in enumerate(syms[1:], start=1): # sym[i] * quat for all points (* is quaternion product) quatComps[i, 0] = (quatComps[0, 0] * sym[0] - quatComps[0, 1] * sym[1] - quatComps[0, 2] * sym[2] - quatComps[0, 3] * sym[3]) quatComps[i, 1] = (quatComps[0, 0] * sym[1] + quatComps[0, 1] * sym[0] - quatComps[0, 2] * sym[3] + quatComps[0, 3] * sym[2]) quatComps[i, 2] = (quatComps[0, 0] * sym[2] + quatComps[0, 2] * sym[0] - quatComps[0, 3] * sym[1] + quatComps[0, 1] * sym[3]) quatComps[i, 3] = (quatComps[0, 0] * sym[3] + quatComps[0, 3] * sym[0] - quatComps[0, 1] * sym[2] + quatComps[0, 2] * sym[1]) # swap into positve hemisphere if required quatComps[i, :, quatComps[i, 0] < 0] *= -1 # Arrays to store neigbour misorientation in positive x and y direction misOrix = np.zeros((numSyms, self.yDim, self.xDim)) misOriy = np.zeros((numSyms, self.yDim, self.xDim)) # loop over symmetries calculating misorientation to initial for i in range(numSyms): for j in range(self.xDim - 1): misOrix[i, :, j] = abs(np.einsum("ij,ij->j", quatComps[0, :, :, j], quatComps[i, :, :, j + 1])) for j in range(self.yDim - 1): misOriy[i, j, :] = abs(np.einsum("ij,ij->j", quatComps[0, :, j, :], quatComps[i, :, j + 1, :])) misOrix[misOrix > 1] = 1 misOriy[misOriy > 1] = 1 # find min misorientation (max here as misorientaion is cos of this) misOrix = np.max(misOrix, axis=0) misOriy = np.max(misOriy, axis=0) # convert to misorientation in degrees misOrix = 360 * np.arccos(misOrix) / np.pi misOriy = 360 * np.arccos(misOriy) / np.pi # set boundary locations where misOrix or misOriy are greater than set value self.boundaries = np.zeros((self.yDim, self.xDim), dtype=int) for i in range(self.xDim): for j in range(self.yDim): if (misOrix[j, i] > boundDef) or (misOriy[j, i] > boundDef): self.boundaries[j, i] = -1 print("\rDone ", end="") return
import numpy as np from defdap.quat import Quat hex_syms = Quat.symEqv("hexagonal") # subset of hexagonal symmetries that give unique orientations when the # Burgers transformation is applied unq_hex_syms = [ hex_syms[0], hex_syms[5], hex_syms[4], hex_syms[2], hex_syms[10], hex_syms[11] ] cubic_syms = Quat.symEqv("cubic") # subset of cubic symmetries that give unique orientations when the # Burgers transformation is applied unq_cub_syms = [ cubic_syms[0], cubic_syms[7], cubic_syms[9], cubic_syms[1], cubic_syms[22], cubic_syms[16], cubic_syms[12], cubic_syms[15], cubic_syms[4], cubic_syms[8], cubic_syms[21], cubic_syms[20] ] # HCP -> BCC burg_eulers = np.array([135, 90, 354.74]) * np.pi / 180 burg_trans = Quat.fromEulerAngles(*burg_eulers).conjugate
def calcNye(self): """ Calculates Nye tensor and related GND density for the EBSD map. Stores result in self.Nye and self.GND. """ self.buildQuatArray() print("\rFinding boundaries...", end="") syms = Quat.symEqv(self.crystalSym) numSyms = len(syms) # array to store quat components of initial and symmetric equivalents quatComps = np.empty((numSyms, 4, self.yDim, self.xDim)) # populate with initial quat components for i, row in enumerate(self.quatArray): for j, quat in enumerate(row): quatComps[0, :, i, j] = quat.quatCoef # loop of over symmetries and apply to initial quat components # (excluding first symmetry as this is the identity transformation) for i, sym in enumerate(syms[1:], start=1): # sym[i] * quat for all points (* is quaternion product) quatComps[i, 0] = (quatComps[0, 0] * sym[0] - quatComps[0, 1] * sym[1] - quatComps[0, 2] * sym[2] - quatComps[0, 3] * sym[3]) quatComps[i, 1] = (quatComps[0, 0] * sym[1] + quatComps[0, 1] * sym[0] - quatComps[0, 2] * sym[3] + quatComps[0, 3] * sym[2]) quatComps[i, 2] = (quatComps[0, 0] * sym[2] + quatComps[0, 2] * sym[0] - quatComps[0, 3] * sym[1] + quatComps[0, 1] * sym[3]) quatComps[i, 3] = (quatComps[0, 0] * sym[3] + quatComps[0, 3] * sym[0] - quatComps[0, 1] * sym[2] + quatComps[0, 2] * sym[1]) # swap into positve hemisphere if required quatComps[i, :, quatComps[i, 0] < 0] *= -1 # Arrays to store neigbour misorientation in positive x and y direction misOrix = np.zeros((numSyms, self.yDim, self.xDim)) misOriy = np.zeros((numSyms, self.yDim, self.xDim)) # loop over symmetries calculating misorientation to initial for i in range(numSyms): for j in range(self.xDim - 1): misOrix[i, :, j] = abs(np.einsum("ij,ij->j", quatComps[0, :, :, j], quatComps[i, :, :, j + 1])) for j in range(self.yDim - 1): misOriy[i, j, :] = abs(np.einsum("ij,ij->j", quatComps[0, :, j, :], quatComps[i, :, j + 1, :])) misOrix[misOrix > 1] = 1 misOriy[misOriy > 1] = 1 # find min misorientation (max here as misorientaion is cos of this) argmisOrix = np.argmax(misOrix, axis=0) argmisOriy = np.argmax(misOriy, axis=0) misOrix = np.max(misOrix, axis=0) misOriy = np.max(misOriy, axis=0) # convert to misorientation in degrees misOrix = 360 * np.arccos(misOrix) / np.pi misOriy = 360 * np.arccos(misOriy) / np.pi # calculate relative elastic distortion tensors at each point in the two directions betaderx = np.zeros((3, 3, self.yDim, self.xDim)) betadery = betaderx for i in range(self.xDim - 1): for j in range(self.yDim - 1): q0x = Quat(quatComps[0, 0, j, i], quatComps[0, 1, j, i], quatComps[0, 2, j, i], quatComps[0, 3, j, i]) qix = Quat(quatComps[argmisOrix[j, i], 0, j, i + 1], quatComps[argmisOrix[j, i], 1, j, i + 1], quatComps[argmisOrix[j, i], 2, j, i + 1], quatComps[argmisOrix[j, i], 3, j, i + 1]) misoquatx = qix.conjugate * q0x # change stepsize to meters betaderx[:, :, j, i] = (Quat.rotMatrix(misoquatx) - np.eye(3)) / self.stepSize / 1e-6 q0y = Quat(quatComps[0, 0, j, i], quatComps[0, 1, j, i], quatComps[0, 2, j, i], quatComps[0, 3, j, i]) qiy = Quat(quatComps[argmisOriy[j, i], 0, j + 1, i], quatComps[argmisOriy[j, i], 1, j + 1, i], quatComps[argmisOriy[j, i], 2, j + 1, i], quatComps[argmisOriy[j, i], 3, j + 1, i]) misoquaty = qiy.conjugate * q0y # change stepsize to meters betadery[:, :, j, i] = (Quat.rotMatrix(misoquaty) - np.eye(3)) / self.stepSize / 1e-6 # Calculate the Nye Tensor alpha = np.empty((3, 3, self.yDim, self.xDim)) bavg = 1.4e-10 # Burgers vector alpha[0, 2] = (betadery[0, 0] - betaderx[0, 1]) / bavg alpha[1, 2] = (betadery[1, 0] - betaderx[1, 1]) / bavg alpha[2, 2] = (betadery[2, 0] - betaderx[2, 1]) / bavg alpha[:, 1] = betaderx[:, 2] / bavg alpha[:, 0] = -1 * betadery[:, 2] / bavg # Calculate 3 possible L1 norms of Nye tensor for total # disloction density alpha_total3 = np.empty((self.yDim, self.xDim)) alpha_total5 = np.empty((self.yDim, self.xDim)) alpha_total9 = np.empty((self.yDim, self.xDim)) alpha_total3 = 30 / 10. *( abs(alpha[0, 2]) + abs(alpha[1, 2]) + abs(alpha[2, 2]) ) alpha_total5 = 30 / 14. * ( abs(alpha[0, 2]) + abs(alpha[1, 2]) + abs(alpha[2, 2]) + abs(alpha[1, 0]) + abs(alpha[0, 1]) ) alpha_total9 = 30 / 20. * ( abs(alpha[0, 2]) + abs(alpha[1, 2]) + abs(alpha[2, 2]) + abs(alpha[0, 0]) + abs(alpha[1, 0]) + abs(alpha[2, 0]) + abs(alpha[0, 1]) + abs(alpha[1, 1]) + abs(alpha[2, 1]) ) alpha_total3[abs(alpha_total3) < 1] = 1e12 alpha_total5[abs(alpha_total3) < 1] = 1e12 alpha_total9[abs(alpha_total3) < 1] = 1e12 # choose from the different alpha_totals according to preference; # see Ruggles GND density paper self.GND = alpha_total9 self.Nye = alpha