def misorientationStats(misorient, *wts): ''' MisorientationStats - Misorientation correlation statistics. USAGE: stats = MisorientationStats(misorient, locations) stats = MisorientationStats(misorient, locations, wts) INPUT: misorient is 4 x n, a list of misorientation quaternions, assumed to have been derived from properly clustered orientation data wts is 1 x n, (optional) a list of weights; if not specified, uniform weights are used OUTPUT: stats is a structure with five components: W is a 3 x 3 matrix (A in Barton paper) Winv is a 3 x 3 matrix (A^-1 in Barton paper) wi is 3 x n, the unnormalized axial vectors REFERENCE: "A Methodology for Determining Average Lattice Orientation and Its Application to the Characterization of Grain Substructure", Nathan R. Barton and Paul R. Dawson, Metallurgical and Materials Transactions A, Volume 32A, August 2001, pp. 1967--1975 ''' misorient = utl.mat2d_row_order(misorient) d, n = misorient.shape if len(wts) == 0: wts = np.tile(1.0 / n, (3, n)) else: wts = np.tile(wts, (3, 1)) wts1 = np.tile(wts[0, :], (4, 1)) misOriCen = sph.SphereAverage(misorient, **{'wts': wts1}) misorient = misorient - np.tile(misOriCen, (1, n)) ang = utl.mat2d_row_order(2 * np.arccos(misorient[0, :])) wsc = np.zeros(ang.shape) limit = (ang < np.finfo(float).eps) nlimit = (ang > np.finfo(float).eps) angn = ang[nlimit] wsc[nlimit] = angn / np.sin(angn / 2) wsc[limit] = 2 wi = misorient[1:4, :] * np.tile(wsc.T, (3, 1)) angax = np.zeros((4, n)) angax[0, :] = np.linalg.norm(wi, axis=0) angax[1:4, :] = normalize(wi, axis=0) Winv = np.sum(utl.RankOneMatrix(wi * wts, wi), axis=2) #We needed to scale this up if it was close to being ill-conditioned if (np.abs(np.linalg.det(Winv)) < 1e-6): if (np.abs(np.linalg.det(Winv)) < 1e-16): W = np.zeros((3, 3)) else: Wtemp = np.multiply(1e9, Winv) W = np.multiply(1e9, np.linalg.inv(Wtemp)) else: W = np.linalg.inv(Winv) stat = {'W': W, 'Winv': Winv, 'wi': wi, 'angaxis': angax} return stat
def bartonStats(misorient, locations, *wts): ''' MisorientationStats - Misorientation correlation statistics. USAGE: stats = MisorientationStats(misorient, locations) stats = MisorientationStats(misorient, locations, wts) INPUT: misorient is 4 x n, a list of misorientation quaternions, assumed to have been derived from properly clustered orientation data locations is d x n, (d <= 3) a list of spatial locations corresponding to the misorientations wts is 1 x n, (optional) a list of weights; if not specified, uniform weights are used OUTPUT: stats is a structure with five components: W is a 3 x 3 matrix (A in Barton paper) X is a d x d matrix (M in Barton paper) WX is a 3 x d matrix (cross-correlation of normalized variables; X in Barton paper) wi is 3 x n, the unnormalized axial vectors xi is d x n, the unnormalized spatial directions from the centroid REFERENCE: "A Methodology for Determining Average Lattice Orientation and Its Application to the Characterization of Grain Substructure", Nathan R. Barton and Paul R. Dawson, Metallurgical and Materials Transactions A, Volume 32A, August 2001, pp. 1967--1975 ''' locations = utl.mat2d_row_order(locations) misorient = utl.mat2d_row_order(misorient) d, n = misorient.shape if len(wts) == 0: wts = np.tile(1.0 / n, (3, n)) else: wts = np.tile(wts, (3, 1)) wts1 = np.tile(wts[0, :], (4, 1)) misOriCen = sph.SphereAverage(misorient, **{'wts': wts1}) misorient = misorient - np.tile(misOriCen, (1, n)) ang = utl.mat2d_row_order(2 * np.arccos(misorient[0, :])) wsc = np.zeros(ang.shape) limit = (ang < np.finfo(float).eps) nlimit = (ang > np.finfo(float).eps) angn = ang[nlimit] wsc[nlimit] = angn / np.sin(angn / 2) wsc[limit] = 2 wi = misorient[1:4, :] * np.tile(wsc.T, (3, 1)) wi = wi * np.tile(ang.T, (3, 1)) cen = utl.mat2d_row_order(np.sum(locations * wts, axis=1)) xi = locations - np.tile(cen, (1, n)) Winv = np.sum(utl.RankOneMatrix(wi * wts, wi), axis=2) Xinv = np.sum(utl.RankOneMatrix(xi * wts, xi), axis=2) #We needed to scale this up if it was close to being ill-conditioned if (np.abs(np.linalg.det(Winv)) < 1e-6): if (np.abs(np.linalg.det(Winv)) < 1e-16): W = np.zeros((3, 3)) else: Wtemp = np.multiply(1e9, Winv) W = np.multiply(1e9, np.linalg.inv(Wtemp)) else: W = np.linalg.inv(Winv) Whalf = sci.linalg.sqrtm(W) if (np.abs(np.linalg.det(Xinv)) < 1e-6): Xtemp = np.multiply(1e9, Xinv) X = np.multiply(1e9, np.linalg.inv(Xtemp)) else: X = np.linalg.inv(Xinv) Xhalf = sci.linalg.sqrtm(X) wibar = np.dot(Whalf, wi) xibar = np.dot(Xhalf, xi) WX = np.sum(utl.RankOneMatrix(wibar * wts, xibar), axis=2) stat = { 'W': W, 'Winv': Winv, 'Xinv': Xinv, 'X': X, 'WX': WX, 'wi': wi, 'xi': xi } return stat