def rotMatOfExpMap_orig(expMap): """ Original rotMatOfExpMap, used for comparison to optimized version """ if isinstance(expMap, ndarray): if expMap.ndim != 2: if expMap.ndim == 1 and len(expMap) == 3: numObjs = 1 expMap = expMap.reshape(3, 1) else: raise RuntimeError("input is the wrong dimensionality") elif expMap.shape[0] != 3: raise RuntimeError( "input is the wrong shape along the 0-axis; " + "Yours is %d when is should be 3" % (expMap.shape[0]) ) else: numObjs = expMap.shape[1] elif isinstance(expMap, list) or isinstance(expMap, tuple): if len(expMap) != 3: raise RuntimeError( "for list/tuple input only one exponential map " + "vector is allowed" ) else: if not isscalar(expMap[0]) or not isscalar(expMap[1]) \ or not isscalar(expMap[2]): raise RuntimeError( "for list/tuple input only one exponential map " + "vector is allowed" ) else: numObjs = 1 expMap = asarray(expMap).reshape(3, 1) phi = columnNorm(expMap) # angles of rotation from exponential maps W = skewMatrixOfVector(expMap) # skew matrices of exponential maps # Find tiny angles to avoid divide-by-zero and apply limits in expressions zeroIndex = phi < cnst.epsf phi[zeroIndex] = 1 # first term C1 = sin(phi) / phi C1[zeroIndex] = 1 # second term C2 = (1 - cos(phi)) / phi**2 C2[zeroIndex] = 1 if numObjs == 1: rmat = I3 + C1 * W + C2 * dot(W, W) else: rmat = zeros((numObjs, 3, 3)) for i in range(numObjs): rmat[i, :, :] = \ I3 + C1[i] * W[i, :, :] + C2[i] * dot(W[i, :, :], W[i, :, :]) return rmat
def contained_in_sst(vectors, vertices_ccw): """ checks hstack array of unit vectors !!! inputs must both be unit vectors !!! vertices must be CCW """ # column-wise normals to the spherical triangle edges sst_normals = np.array([ np.cross(vertices_ccw[:, i[0]], vertices_ccw[:, i[1]]) for i in [(0, 1), (1, 2), (2, 0)] ]).T sst_normals_unit = mutil.unitVector(sst_normals) angles = np.arcsin(mutil.columnNorm(sst_normals)) edges = [] for i, ang in enumerate(angles): sub_ang = np.linspace(0, ang, endpoint=True) for j in sub_ang: rm = rot.rotMatOfExpMap(j * sst_normals_unit[:, i].reshape(3, 1)) edges.append(np.dot(vertices_ccw[:, i], rm.T)) edges.append(np.nan * np.ones(3)) dim, n = vectors.shape contained = [] for v in vectors.T: d0 = np.dot(sst_normals_unit[:, 0], v) d1 = np.dot(sst_normals_unit[:, 1], v) d2 = np.dot(sst_normals_unit[:, 2], v) contained.append(np.all([d0 > 0, d1 > 0, d2 > 0])) return contained, np.vstack(edges)
def quatOfExpMap(expMap): """ """ angles = columnNorm(expMap) axes = unitVector(expMap) quats = quatOfAngleAxis(angles, axes) return quats
def rotMatOfExpMap_opt(expMap): """Optimized version of rotMatOfExpMap """ if expMap.ndim == 1: expMap = expMap.reshape(3, 1) # angles of rotation from exponential maps phi = atleast_1d(columnNorm(expMap)) # skew matrices of exponential maps W = skewMatrixOfVector(expMap) # Find tiny angles to avoid divide-by-zero and apply limits in expressions zeroIndex = phi < cnst.epsf phi[zeroIndex] = 1 # first term C1 = sin(phi) / phi C1[zeroIndex] = 1 # is this right? might be OK since C1 multiplies W # second term C2 = (1 - cos(phi)) / phi**2 C2[zeroIndex] = 0.5 # won't matter because W^2 is small numObjs = expMap.shape[1] if numObjs == 1: # case of single point W = np.reshape(W, [1, 3, 3]) pass C1 = np.tile( np.reshape(C1, [numObjs, 1]), [1, 9]).reshape([numObjs, 3, 3]) C2 = np.tile( np.reshape(C2, [numObjs, 1]), [1, 9]).reshape([numObjs, 3, 3]) W2 = np.zeros([numObjs, 3, 3]) for i in range(3): for j in range(3): W2[:, i, j] = np.sum(W[:, i, :]*W[:, :, j], 1) pass pass rmat = C1*W + C2 * W2 rmat[:, 0, 0] += 1. rmat[:, 1, 1] += 1. rmat[:, 2, 2] += 1. return rmat.squeeze()
def rotMatOfExpMap_orig(expMap): """Original rotMatOfExpMap, used for comparison to optimized version """ if isinstance(expMap, ndarray): if expMap.ndim != 2: if expMap.ndim == 1 and len(expMap) == 3: numObjs = 1 expMap = expMap.reshape(3, 1) else: raise RuntimeError, "input is the wrong dimensionality" elif expMap.shape[0] != 3: raise RuntimeError( "input is the wrong shape along the 0-axis. Yours is %d when is should be 3" % (expMap.shape[0]) ) else: numObjs = expMap.shape[1] elif isinstance(expMap, list) or isinstance(expMap, tuple): if len(expMap) != 3: raise RuntimeError, "for list/tuple input only one exponential map vector is allowed" else: if not isscalar(expMap[0]) or not isscalar(expMap[1]) or not isscalar(expMap[2]): raise RuntimeError, "for list/tuple input only one exponential map vector is allowed" else: numObjs = 1 expMap = asarray(expMap).reshape(3, 1) phi = columnNorm(expMap) # angles of rotation from exponential maps W = skewMatrixOfVector(expMap) # skew matrices of exponential maps # Find tiny angles to avoid divide-by-zero and apply limits in expressions zeroIndex = phi < tinyRotAng phi[zeroIndex] = 1 # first term C1 = sin(phi) / phi C1[zeroIndex] = 1 # second term C2 = (1 - cos(phi)) / phi ** 2 C2[zeroIndex] = 1 if numObjs == 1: rmat = I3 + C1 * W + C2 * dot(W, W) else: rmat = zeros((numObjs, 3, 3)) for i in range(numObjs): rmat[i, :, :] = I3 + C1[i] * W[i, :, :] + C2[i] * dot(W[i, :, :], W[i, :, :]) return rmat
def rotMatOfExpMap_opt(expMap): """Optimized version of rotMatOfExpMap """ if expMap.ndim == 1: expMap = expMap.reshape(3, 1) phi = atleast_1d(columnNorm(expMap)) # angles of rotation from exponential maps W = skewMatrixOfVector(expMap) # skew matrices of exponential maps # Find tiny angles to avoid divide-by-zero and apply limits in expressions zeroIndex = phi < tinyRotAng phi[zeroIndex] = 1 # first term C1 = sin(phi) / phi C1[zeroIndex] = 1 # is this right? might be OK since C1 multiplies W # second term C2 = (1 - cos(phi)) / phi**2 C2[zeroIndex] = 0.5 # won't matter because W^2 is small numObjs = expMap.shape[1] if numObjs == 1: # case of single point W = numpy.reshape(W, [1, 3, 3]) pass C1 = numpy.tile(numpy.reshape(C1, [numObjs, 1]), [1, 9]).reshape([numObjs,3,3]) C2 = numpy.tile(numpy.reshape(C2, [numObjs, 1]), [1, 9]).reshape([numObjs,3,3]) W2 = numpy.zeros([numObjs, 3, 3]) for i in range(3): for j in range(3): W2[:, i, j] = numpy.sum(W[:, i, :]*W[:, :, j], 1) pass pass rmat = C1*W + C2 * W2 rmat[:, 0, 0] += 1. rmat[:, 1, 1] += 1. rmat[:, 2, 2] += 1. return rmat.squeeze()
def assemble_grain_data(grain_data_list, pos_offset=None, rotation_offset=None): num_grain_files = len(grain_data_list) num_grains_list = [None] * num_grain_files for i in np.arange(num_grain_files): num_grains_list[i] = grain_data_list[i].shape[0] num_grains = np.sum(num_grains_list) grain_data = np.zeros([num_grains, grain_data_list[0].shape[1]]) for i in np.arange(num_grain_files): tmp = copy.copy(grain_data_list[i]) if pos_offset is not None: pos_tile = np.tile(pos_offset[:, i], [num_grains_list[i], 1]) tmp[:, 6:9] = tmp[:, 6:9] + pos_tile #Needs Testing if rotation_offset is not None: rot_tile = np.tile( np.atleast_2d(rotation_offset[:, i]).T, [1, num_grains_list[i]]) quat_tile = rot.quatOfExpMap(rot_tile) grain_quats = rot.quatOfExpMap(tmp[:, 3:6].T) new_quats = rot.quatProduct(grain_quats, quat_tile) sinang = mutil.columnNorm(new_quats[1:, :]) ang = 2. * np.arcsin(sinang) axis = mutil.unitVector(new_quats[1:, :]) tmp[:, 3:6] = np.tile(np.atleast_2d(ang).T, [1, 3]) * axis.T grain_data[int(np.sum(num_grains_list[:i]) ):int(np.sum(num_grains_list[:(i + 1)])), :] = tmp old_grain_numbers = copy.copy(grain_data[:, 0]) grain_data[:, 0] = np.arange(num_grains) return grain_data, old_grain_numbers
def assemble_grain_data(grain_data_list,pos_offset=None,rotation_offset=None): num_grain_files=len(grain_data_list) num_grains_list=[None]*num_grain_files for i in np.arange(num_grain_files): num_grains_list[i]=grain_data_list[i].shape[0] num_grains=np.sum(num_grains_list) grain_data=np.zeros([num_grains,grain_data_list[0].shape[1]]) for i in np.arange(num_grain_files): tmp=copy.copy(grain_data_list[i]) if pos_offset is not None: pos_tile=np.tile(pos_offset[:,i],[num_grains_list[i],1]) tmp[:,6:9]=tmp[:,6:9]+pos_tile #Needs Testing if rotation_offset is not None: rot_tile=np.tile(np.atleast_2d(rotation_offset[:,i]).T,[1,num_grains_list[i]]) quat_tile=rot.quatOfExpMap(rot_tile) grain_quats=rot.quatOfExpMap(tmp[:,3:6].T) new_quats=rot.quatProduct(grain_quats,quat_tile) sinang = mutil.columnNorm(new_quats[1:,:]) ang=2.*np.arcsin(sinang) axis = mutil.unitVector(new_quats[1:,:]) tmp[:,3:6]=np.tile(np.atleast_2d(ang).T,[1,3])*axis.T grain_data[int(np.sum(num_grains_list[:i])):int(np.sum(num_grains_list[:(i+1)])),:]=tmp old_grain_numbers=copy.copy(grain_data[:,0]) grain_data[:,0]=np.arange(num_grains) return grain_data,old_grain_numbers
def discreteFiber(c, s, B=I3, ndiv=120, invert=False, csym=None, ssym=None): """ """ import symmetry as S ztol = 1.e-8 # arg handling for c if hasattr(c, '__len__'): if hasattr(c, 'shape'): assert c.shape[0] == 3, \ 'scattering vector must be 3-d; yours is %d-d' \ % (c.shape[0]) if len(c.shape) == 1: c = c.reshape(3, 1) elif len(c.shape) > 2: raise RuntimeError, \ 'incorrect arg shape; must be 1-d or 2-d, yours is %d-d' \ % (len(c.shape)) else: # convert list input to array and transpose if len(c) == 3 and isscalar(c[0]): c = asarray(c).reshape(3, 1) else: c = asarray(c).T else: raise RuntimeError, 'input must be array-like' # arg handling for s if hasattr(s, '__len__'): if hasattr(s, 'shape'): assert s.shape[0] == 3, \ 'scattering vector must be 3-d; yours is %d-d' \ % (s.shape[0]) if len(s.shape) == 1: s = s.reshape(3, 1) elif len(s.shape) > 2: raise RuntimeError, \ 'incorrect arg shape; must be 1-d or 2-d, yours is %d-d' \ % (len(s.shape)) else: # convert list input to array and transpose if len(s) == 3 and isscalar(s[0]): s = asarray(s).reshape(3, 1) else: s = asarray(s).T else: raise RuntimeError, 'input must be array-like' nptc = c.shape[1] npts = s.shape[1] c = unitVector(dot(B, c)) # turn c hkls into unit vector in crys frame s = unitVector(s) # convert s to unit vector in samp frame retval = [] for i_c in range(nptc): dupl_c = tile(c[:, i_c], (npts, 1)).T ax = s + dupl_c anrm = columnNorm(ax).squeeze() # should be 1-d okay = anrm > ztol nokay = okay.sum() if nokay == npts: ax = ax / tile(anrm, (3, 1)) else: nspace = nullSpace(c[:, i_c].reshape(3, 1)) hperp = nspace[:, 0].reshape(3, 1) if nokay == 0: ax = tile(hperp, (1, npts)) else: ax[:, okay] = ax[:, okay] / tile(anrm[okay], (3, 1)) ax[:, not okay] = tile(hperp, (1, npts - nokay)) q0 = vstack( [ zeros(npts), ax ] ) # find rotations # note: the following line fixes bug with use of arange with float increments phi = arange(0, ndiv) * (2*pi/float(ndiv)) qh = quatOfAngleAxis(phi, tile(c[:, i_c], (ndiv, 1)).T) # the fibers, arraged as (npts, 4, ndiv) qfib = dot( quatProductMatrix(qh, mult='right'), q0 ).transpose(2, 1, 0) if csym is not None: retval.append(S.toFundamentalRegion(qfib.squeeze(), crysSym=csym, sampSym=ssym)) else: retval.append(fixQuat(qfib).squeeze()) return retval
def oe_pfig(self): """Make an omega-eta polefigure""" # some constants deg2rad = numpy.pi / 180.0 radius = numpy.sqrt(2) offset = 2.5 * radius nocolor = 'none' pdir_cho = 'X' # to come from choice interactor # parent window and data exp = wx.GetApp().ws p = self.GetParent() ome_eta = p.data hkldata = ome_eta.getData(self.idata) # axes/figure p.figure.delaxes(p.axes) p.axes = p.figure.gca() p.axes.set_autoscale_on(True) p.axes.set_aspect('equal') p.axes.axis([-2.0, offset + 2.0, -1.5, 1.5]) # outlines for pole figure C1 = Circle((0, 0), radius) C2 = Circle((offset, 0), radius) outline_circles = [C1, C2] pc_outl = PatchCollection(outline_circles, facecolors=nocolor) p.axes.add_collection(pc_outl) # build the rectangles pf_rects = [] tTh = exp.activeMaterial.planeData.getTTh()[self.idata] etas = ome_eta.etaEdges netas = len(etas) - 1 deta = abs(etas[1] - etas[0]) omes = ome_eta.omeEdges nomes = len(omes) - 1 dome = abs(omes[1] - omes[0]) if pdir_cho == 'X': pdir = numpy.c_[1, 0, 0].T # X elif pdir_cho == 'Y': pdir = numpy.c_[0, 1, 0].T # X elif pdir_cho == 'Z': pdir = numpy.c_[0, 0, 1].T # X pass ii = 0 for i in range(nomes): for j in range(netas): qc = makeMSV(tTh, etas[j] + 0.5 * deta, omes[i] + 0.5 * dome) qll = makeMSV(tTh, etas[j], omes[i]) qlr = makeMSV(tTh, etas[j] + deta, omes[i]) qur = makeMSV(tTh, etas[j] + deta, omes[i] + dome) qul = makeMSV(tTh, etas[j], omes[i] + dome) pdot_p = numpy.dot(qll.T, pdir) >= 0 \ and numpy.dot(qlr.T, pdir) >= 0 \ and numpy.dot(qur.T, pdir) >= 0 \ and numpy.dot(qul.T, pdir) >= 0 pdot_m = numpy.dot(qll.T, pdir) < 0 \ and numpy.dot(qlr.T, pdir) < 0 \ and numpy.dot(qur.T, pdir) < 0 \ and numpy.dot(qul.T, pdir) < 0 if pdot_p: sgn = 1.0 ii += 1 elif pdot_m: sgn = -1.0 ii += 1 elif not pdot_p and not pdot_m: continue # the vertex chords qll = makeMSV(tTh, etas[j], omes[i]) - sgn * pdir qlr = makeMSV(tTh, etas[j] + deta, omes[i]) - sgn * pdir qur = makeMSV(tTh, etas[j] + deta, omes[i] + dome) - sgn * pdir qul = makeMSV(tTh, etas[j], omes[i] + dome) - sgn * pdir nll = columnNorm(qll) nlr = columnNorm(qlr) nur = columnNorm(qur) nul = columnNorm(qul) if pdir_cho == 'X': pqll = nll * unitVector(qll[[1, 2]].reshape(2, 1)) pqlr = nlr * unitVector(qlr[[1, 2]].reshape(2, 1)) pqur = nur * unitVector(qur[[1, 2]].reshape(2, 1)) pqul = nul * unitVector(qul[[1, 2]].reshape(2, 1)) elif pdir_cho == 'Y': pqll = nll * unitVector(qll[[0, 2]].reshape(2, 1)) pqlr = nlr * unitVector(qlr[[0, 2]].reshape(2, 1)) pqur = nur * unitVector(qur[[0, 2]].reshape(2, 1)) pqul = nul * unitVector(qul[[0, 2]].reshape(2, 1)) elif pdir_cho == 'Z': pqll = nll * unitVector(qll[[0, 1]].reshape(2, 1)) pqlr = nlr * unitVector(qlr[[0, 1]].reshape(2, 1)) pqur = nur * unitVector(qur[[0, 1]].reshape(2, 1)) pqul = nul * unitVector(qul[[0, 1]].reshape(2, 1)) xy = numpy.hstack([pqll, pqlr, pqur, pqul]).T if sgn == -1: xy[:, 0] = xy[:, 0] + offset pf_rects.append(Polygon(xy, aa=False)) pass pass cmap = matplotlib.cm.jet pf_coll = PatchCollection(pf_rects, cmap=cmap, edgecolors='None') pf_coll.set_array(numpy.array(hkldata.T.flatten())) p.axes.add_collection(pf_coll) p.canvas.draw() p.axes.axis('off') return
def simulateLauePattern(self, planeData, minEnergy=5, maxEnergy=25, rMat_s=np.eye(3), rMat=None, vInv=None, doGnomonic=False): multipleEnergyRanges = False if hasattr(maxEnergy, '__len__'): assert len(maxEnergy) == len(minEnergy), 'energy cutoff ranges must have the same length' multipleEnergyRanges = True; lmin = []; lmax = [] for i in range(len(maxEnergy)): lmin.append(processWavelength(maxEnergy[i])) lmax.append(processWavelength(minEnergy[i])) else: lmin = processWavelength(maxEnergy) lmax = processWavelength(minEnergy) gvec_c = planeData.getPlaneNormals() hkls = planeData.getSymHKLs() dsp = planeData.getPlaneSpacings() if rMat is None: rMat = [np.eye(3),] if vInv is None: vInv = [vInv_ref,] # rMult = planeData.getMultiplicity() # nHKLs_tot = rMult.sum() # rMask = np.ones(nHKLs_tot, dtype=bool) retval = [] for iG in range(len(rMat)): tmp = {'detXY':[], 'gnoXY':[], 'angles':[], 'dspacing':[], 'hkl':[], 'energy':[]} for iHKL in range(planeData.nHKLs): # stretch them: V^(-1) * R * Gc gvec_s_str = mutil.unitVector( np.dot( vInv[iG], np.dot( rMat[iG], gvec_c[iHKL] ) ) ) gvec_c_str = np.dot(rMat[iG].T, gvec_s_str) gvec_l_str = np.dot(rMat_s, gvec_s_str) # # dpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s) # gpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s, doGnomonic=True) dpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s) gpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s, doGnomonic=True) canIntersect = -np.isnan(dpts[0, :]) npts_in = sum(canIntersect) if np.any(canIntersect): dpts = dpts[:, canIntersect].reshape(3, npts_in) dhkl = hkls[iHKL][:, canIntersect].reshape(3, npts_in) gvl_hat = gvec_l_str[:, canIntersect].reshape(3, npts_in) gvl_xy = gvec_l_str[:2, canIntersect].reshape(2, npts_in) # dot with the beam dotWbeam = np.dot(Z_ref.T, gvl_hat).flatten() # angles theta = piby2 - rot.arccosSafe( dotWbeam ) wlen = 2*dsp[iHKL]*np.sin(theta) eta = np.arccos(gvl_xy[0, :]) # find on spatial extent of detector # for corner # xTest = np.logical_and(dpts[0, :] > 0, dpts[0, :] < self.cdim) # for corner # yTest = np.logical_and(dpts[1, :] > 0, dpts[1, :] < self.rdim) xTest = np.logical_and(dpts[0, :] > -0.5 * self.cdim, dpts[0, :] < 0.5 * self.cdim) yTest = np.logical_and(dpts[1, :] > -0.5 * self.rdim, dpts[1, :] < 0.5 * self.rdim) onDetector = np.logical_and(xTest, yTest) if multipleEnergyRanges: validEnergy = np.zeros(len(wlen), dtype=bool) for i in range(len(lmin)): validEnergy = validEnergy | np.logical_and(wlen >= lmin[i], wlen <= lmax[i]) pass else: validEnergy = np.logical_and(wlen >= lmin, wlen <= lmax) pass keepers = np.logical_and(onDetector, validEnergy) dsp_this = 1. / mutil.columnNorm(np.dot(planeData.latVecOps['B'], dhkl[:, keepers])) tmp['detXY'].append(dpts[:2, keepers]) tmp['gnoXY'].append(gpts[:2, keepers]) tmp['angles'].append(np.vstack([2*theta[keepers]*r2d, eta[keepers]*r2d])) tmp['hkl'].append(dhkl[:, keepers]) tmp['dspacing'].append(dsp_this) tmp['energy'].append(processWavelength(wlen[keepers])) else: tmp['detXY'].append(np.empty((2, 0))) tmp['gnoXY'].append(np.empty((2, 0))) tmp['angles'].append(np.empty((2, 0))) tmp['hkl'].append(np.empty((3, 0))) tmp['dspacing'].append(np.empty(0)) tmp['energy'].append(np.empty(0)) pass pass retval.append(tmp) return retval
def oe_pfig(self): """Make an omega-eta polefigure""" # some constants deg2rad = numpy.pi /180.0 radius = numpy.sqrt(2) offset = 2.5*radius nocolor = 'none' pdir_cho = 'X' # to come from choice interactor # parent window and data exp = wx.GetApp().ws p = self.GetParent() ome_eta = p.data hkldata = ome_eta.getData(self.idata) # axes/figure p.figure.delaxes(p.axes) p.axes = p.figure.gca() p.axes.set_autoscale_on(True) p.axes.set_aspect('equal') p.axes.axis([-2.0, offset+2.0, -1.5, 1.5]) # outlines for pole figure C1 = Circle((0,0), radius) C2 = Circle((offset,0), radius) outline_circles = [C1, C2] pc_outl = PatchCollection(outline_circles, facecolors=nocolor) p.axes.add_collection(pc_outl) # build the rectangles pf_rects = [] tTh = exp.activeMaterial.planeData.getTTh()[self.idata] etas = ome_eta.etaEdges netas = len(etas) - 1 deta = abs(etas[1] - etas[0]) omes = ome_eta.omeEdges nomes = len(omes) - 1 dome = abs(omes[1] - omes[0]) if pdir_cho == 'X': pdir = numpy.c_[1, 0, 0].T # X elif pdir_cho == 'Y': pdir = numpy.c_[0, 1, 0].T # X elif pdir_cho == 'Z': pdir = numpy.c_[0, 0, 1].T # X pass ii = 0 for i in range(nomes): for j in range(netas): qc = makeMSV(tTh, etas[j] + 0.5*deta, omes[i] + 0.5*dome) qll = makeMSV(tTh, etas[j], omes[i]) qlr = makeMSV(tTh, etas[j] + deta, omes[i]) qur = makeMSV(tTh, etas[j] + deta, omes[i] + dome) qul = makeMSV(tTh, etas[j], omes[i] + dome) pdot_p = numpy.dot(qll.T, pdir) >= 0 \ and numpy.dot(qlr.T, pdir) >= 0 \ and numpy.dot(qur.T, pdir) >= 0 \ and numpy.dot(qul.T, pdir) >= 0 pdot_m = numpy.dot(qll.T, pdir) < 0 \ and numpy.dot(qlr.T, pdir) < 0 \ and numpy.dot(qur.T, pdir) < 0 \ and numpy.dot(qul.T, pdir) < 0 if pdot_p: sgn = 1.0 ii += 1 elif pdot_m: sgn = -1.0 ii += 1 elif not pdot_p and not pdot_m: continue # the vertex chords qll = makeMSV(tTh, etas[j], omes[i]) - sgn * pdir qlr = makeMSV(tTh, etas[j] + deta, omes[i]) - sgn * pdir qur = makeMSV(tTh, etas[j] + deta, omes[i] + dome) - sgn * pdir qul = makeMSV(tTh, etas[j], omes[i] + dome) - sgn * pdir nll = columnNorm(qll) nlr = columnNorm(qlr) nur = columnNorm(qur) nul = columnNorm(qul) if pdir_cho == 'X': pqll = nll*unitVector(qll[[1, 2]].reshape(2, 1)) pqlr = nlr*unitVector(qlr[[1, 2]].reshape(2, 1)) pqur = nur*unitVector(qur[[1, 2]].reshape(2, 1)) pqul = nul*unitVector(qul[[1, 2]].reshape(2, 1)) elif pdir_cho == 'Y': pqll = nll*unitVector(qll[[0, 2]].reshape(2, 1)) pqlr = nlr*unitVector(qlr[[0, 2]].reshape(2, 1)) pqur = nur*unitVector(qur[[0, 2]].reshape(2, 1)) pqul = nul*unitVector(qul[[0, 2]].reshape(2, 1)) elif pdir_cho == 'Z': pqll = nll*unitVector(qll[[0, 1]].reshape(2, 1)) pqlr = nlr*unitVector(qlr[[0, 1]].reshape(2, 1)) pqur = nur*unitVector(qur[[0, 1]].reshape(2, 1)) pqul = nul*unitVector(qul[[0, 1]].reshape(2, 1)) xy = numpy.hstack([pqll, pqlr, pqur, pqul]).T if sgn == -1: xy[:, 0] = xy[:, 0] + offset pf_rects.append(Polygon(xy, aa=False)) pass pass cmap=matplotlib.cm.jet pf_coll = PatchCollection(pf_rects, cmap=cmap, edgecolors='None') pf_coll.set_array(numpy.array(hkldata.T.flatten())) p.axes.add_collection(pf_coll) p.canvas.draw() p.axes.axis('off') return
def discreteFiber(c, s, B=I3, ndiv=120, invert=False, csym=None, ssym=None): """ """ import symmetry as S ztol = 1.e-8 # arg handling for c if hasattr(c, '__len__'): if hasattr(c, 'shape'): assert c.shape[0] == 3, \ 'scattering vector must be 3-d; yours is %d-d' \ % (c.shape[0]) if len(c.shape) == 1: c = c.reshape(3, 1) elif len(c.shape) > 2: raise RuntimeError, \ 'incorrect arg shape; must be 1-d or 2-d, yours is %d-d' \ % (len(c.shape)) else: # convert list input to array and transpose if len(c) == 3 and isscalar(c[0]): c = asarray(c).reshape(3, 1) else: c = asarray(c).T else: raise RuntimeError, 'input must be array-like' # arg handling for s if hasattr(s, '__len__'): if hasattr(s, 'shape'): assert s.shape[0] == 3, \ 'scattering vector must be 3-d; yours is %d-d' \ % (s.shape[0]) if len(s.shape) == 1: s = s.reshape(3, 1) elif len(s.shape) > 2: raise RuntimeError, \ 'incorrect arg shape; must be 1-d or 2-d, yours is %d-d' \ % (len(s.shape)) else: # convert list input to array and transpose if len(s) == 3 and isscalar(s[0]): s = asarray(s).reshape(3, 1) else: s = asarray(s).T else: raise RuntimeError, 'input must be array-like' nptc = c.shape[1] npts = s.shape[1] c = unitVector(dot(B, c)) # turn c hkls into unit vector in crys frame s = unitVector(s) # convert s to unit vector in samp frame retval = [] for i_c in range(nptc): dupl_c = tile(c[:, i_c], (npts, 1)).T ax = s + dupl_c anrm = columnNorm(ax).squeeze() # should be 1-d okay = anrm > ztol nokay = okay.sum() if nokay == npts: ax = ax / tile(anrm, (3, 1)) else: nspace = nullSpace(c[:, i_c].reshape(3, 1)) hperp = nspace[:, 0].reshape(3, 1) if nokay == 0: ax = tile(hperp, (1, npts)) else: ax[:, okay] = ax[:, okay] / tile(anrm[okay], (3, 1)) ax[:, not okay] = tile(hperp, (1, npts - nokay)) q0 = vstack([zeros(npts), ax]) # find rotations # note: the following line fixes bug with use of arange with float increments phi = arange(0, ndiv) * (2 * pi / float(ndiv)) qh = quatOfAngleAxis(phi, tile(c[:, i_c], (ndiv, 1)).T) # the fibers, arraged as (npts, 4, ndiv) qfib = dot(quatProductMatrix(qh, mult='right'), q0).transpose(2, 1, 0) if csym is not None: retval.append( S.toFundamentalRegion(qfib.squeeze(), crysSym=csym, sampSym=ssym)) else: retval.append(fixQuat(qfib).squeeze()) return retval
def simulateLauePattern(hkls, bMat, rmat_d, tvec_d, panel_dims, panel_buffer=5, minEnergy=8, maxEnergy=24, rmat_s=np.eye(3), grain_params=None, distortion=None, beamVec=None): if beamVec is None: beamVec = xfcapi.bVec_ref # parse energy ranges multipleEnergyRanges = False if hasattr(maxEnergy, '__len__'): assert len(maxEnergy) == len(minEnergy), \ 'energy cutoff ranges must have the same length' multipleEnergyRanges = True lmin = [] lmax = [] for i in range(len(maxEnergy)): lmin.append(processWavelength(maxEnergy[i])) lmax.append(processWavelength(minEnergy[i])) else: lmin = processWavelength(maxEnergy) lmax = processWavelength(minEnergy) # process crystal rmats and inverse stretches if grain_params is None: grain_params = np.atleast_2d( [0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.]) n_grains = len(grain_params) # dummy translation vector... make input tvec_s = np.zeros((3, 1)) # number of hkls nhkls_tot = hkls.shape[1] # unit G-vectors in crystal frame ghat_c = mutil.unitVector(np.dot(bMat, hkls)) # pre-allocate output arrays xy_det = np.nan * np.ones((n_grains, nhkls_tot, 2)) hkls_in = np.nan * np.ones((n_grains, 3, nhkls_tot)) angles = np.nan * np.ones((n_grains, nhkls_tot, 2)) dspacing = np.nan * np.ones((n_grains, nhkls_tot)) energy = np.nan * np.ones((n_grains, nhkls_tot)) """ LOOP OVER GRAINS """ for iG, gp in enumerate(grain_params): rmat_c = xfcapi.makeRotMatOfExpMap(gp[:3]) tvec_c = gp[3:6].reshape(3, 1) vInv_s = mutil.vecMVToSymm(gp[6:].reshape(6, 1)) # stretch them: V^(-1) * R * Gc ghat_s_str = mutil.unitVector(np.dot(vInv_s, np.dot(rmat_c, ghat_c))) ghat_c_str = np.dot(rmat_c.T, ghat_s_str) # project dpts = xfcapi.gvecToDetectorXY(ghat_c_str.T, rmat_d, rmat_s, rmat_c, tvec_d, tvec_s, tvec_c, beamVec=beamVec).T # check intersections with detector plane canIntersect = ~np.isnan(dpts[0, :]) npts_in = sum(canIntersect) if np.any(canIntersect): dpts = dpts[:, canIntersect].reshape(2, npts_in) dhkl = hkls[:, canIntersect].reshape(3, npts_in) # back to angles tth_eta, gvec_l = xfcapi.detectorXYToGvec(dpts.T, rmat_d, rmat_s, tvec_d, tvec_s, tvec_c, beamVec=beamVec) tth_eta = np.vstack(tth_eta).T # warp measured points if distortion is not None: if len(distortion) == 2: dpts = distortion[0](dpts, distortion[1], invert=True) # plane spacings and energies dsp = 1. / mutil.columnNorm(np.dot(bMat, dhkl)) wlen = 2 * dsp * np.sin(0.5 * tth_eta[:, 0]) # find on spatial extent of detector xTest = np.logical_and( dpts[0, :] >= -0.5 * panel_dims[1] + panel_buffer, dpts[0, :] <= 0.5 * panel_dims[1] - panel_buffer) yTest = np.logical_and( dpts[1, :] >= -0.5 * panel_dims[0] + panel_buffer, dpts[1, :] <= 0.5 * panel_dims[0] - panel_buffer) onDetector = np.logical_and(xTest, yTest) if multipleEnergyRanges: validEnergy = np.zeros(len(wlen), dtype=bool) for i in range(len(lmin)): validEnergy = validEnergy | \ np.logical_and(wlen >= lmin[i], wlen <= lmax[i]) pass else: validEnergy = np.logical_and(wlen >= lmin, wlen <= lmax) pass # index for valid reflections keepers = np.where(np.logical_and(onDetector, validEnergy))[0] # assign output arrays xy_det[iG][keepers, :] = dpts[:, keepers].T hkls_in[iG][:, keepers] = dhkl[:, keepers] angles[iG][keepers, :] = tth_eta[keepers, :] dspacing[iG, keepers] = dsp[keepers] energy[iG, keepers] = processWavelength(wlen[keepers]) pass pass return xy_det, hkls_in, angles, dspacing, energy
def simulateLauePattern(self, planeData, minEnergy=5, maxEnergy=25, rMat_s=np.eye(3), rMat=None, vInv=None, doGnomonic=False): multipleEnergyRanges = False if hasattr(maxEnergy, '__len__'): assert len(maxEnergy) == len( minEnergy), 'energy cutoff ranges must have the same length' multipleEnergyRanges = True lmin = [] lmax = [] for i in range(len(maxEnergy)): lmin.append(processWavelength(maxEnergy[i])) lmax.append(processWavelength(minEnergy[i])) else: lmin = processWavelength(maxEnergy) lmax = processWavelength(minEnergy) gvec_c = planeData.getPlaneNormals() hkls = planeData.getSymHKLs() dsp = planeData.getPlaneSpacings() if rMat is None: rMat = [ np.eye(3), ] if vInv is None: vInv = [ vInv_ref, ] # rMult = planeData.getMultiplicity() # nHKLs_tot = rMult.sum() # rMask = np.ones(nHKLs_tot, dtype=bool) retval = [] for iG in range(len(rMat)): tmp = { 'detXY': [], 'gnoXY': [], 'angles': [], 'dspacing': [], 'hkl': [], 'energy': [] } for iHKL in range(planeData.nHKLs): # stretch them: V^(-1) * R * Gc gvec_s_str = mutil.unitVector( np.dot(vInv[iG], np.dot(rMat[iG], gvec_c[iHKL]))) gvec_c_str = np.dot(rMat[iG].T, gvec_s_str) gvec_l_str = np.dot(rMat_s, gvec_s_str) # # dpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s) # gpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s, doGnomonic=True) dpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s) gpts = self.gVecToDet(gvec_c_str, rMat=rMat[iG], rMat_s=rMat_s, doGnomonic=True) canIntersect = -np.isnan(dpts[0, :]) npts_in = sum(canIntersect) if np.any(canIntersect): dpts = dpts[:, canIntersect].reshape(3, npts_in) dhkl = hkls[iHKL][:, canIntersect].reshape(3, npts_in) gvl_hat = gvec_l_str[:, canIntersect].reshape(3, npts_in) gvl_xy = gvec_l_str[:2, canIntersect].reshape(2, npts_in) # dot with the beam dotWbeam = np.dot(Z_ref.T, gvl_hat).flatten() # angles theta = piby2 - rot.arccosSafe(dotWbeam) wlen = 2 * dsp[iHKL] * np.sin(theta) eta = np.arccos(gvl_xy[0, :]) # find on spatial extent of detector # for corner # xTest = np.logical_and(dpts[0, :] > 0, dpts[0, :] < self.cdim) # for corner # yTest = np.logical_and(dpts[1, :] > 0, dpts[1, :] < self.rdim) xTest = np.logical_and(dpts[0, :] > -0.5 * self.cdim, dpts[0, :] < 0.5 * self.cdim) yTest = np.logical_and(dpts[1, :] > -0.5 * self.rdim, dpts[1, :] < 0.5 * self.rdim) onDetector = np.logical_and(xTest, yTest) if multipleEnergyRanges: validEnergy = np.zeros(len(wlen), dtype=bool) for i in range(len(lmin)): validEnergy = validEnergy | np.logical_and( wlen >= lmin[i], wlen <= lmax[i]) pass else: validEnergy = np.logical_and(wlen >= lmin, wlen <= lmax) pass keepers = np.logical_and(onDetector, validEnergy) dsp_this = 1. / mutil.columnNorm( np.dot(planeData.latVecOps['B'], dhkl[:, keepers])) tmp['detXY'].append(dpts[:2, keepers]) tmp['gnoXY'].append(gpts[:2, keepers]) tmp['angles'].append( np.vstack( [2 * theta[keepers] * r2d, eta[keepers] * r2d])) tmp['hkl'].append(dhkl[:, keepers]) tmp['dspacing'].append(dsp_this) tmp['energy'].append(processWavelength(wlen[keepers])) else: tmp['detXY'].append(np.empty((2, 0))) tmp['gnoXY'].append(np.empty((2, 0))) tmp['angles'].append(np.empty((2, 0))) tmp['hkl'].append(np.empty((3, 0))) tmp['dspacing'].append(np.empty(0)) tmp['energy'].append(np.empty(0)) pass pass retval.append(tmp) return retval
def makeScatteringVectors(hkls, rMat_c, bMat, wavelength, chiTilt=None): """ modeled after QFromU.m """ # basis vectors bHat_l = num.c_[ 0., 0., -1.].T eHat_l = num.c_[ 1., 0., 0.].T zTol = 1.0e-7 # zero tolerance for checking vectors gVec_s = [] oangs0 = [] oangs1 = [] # these are the reciprocal lattice vectors in the CRYSTAL FRAME # ** NOTE ** # if strained, assumes that you handed it a bMat calculated from # strained [a, b, c] gVec_c = num.dot( bMat, hkls ) gHat_c = unitVector(gVec_c) dim0, nRefl = gVec_c.shape assert dim0 == 3, "Looks like something is wrong with your lattice plane normals son!" # extract 1/dspacing and sin of bragg angle dSpacingi = columnNorm(gVec_c).flatten() sintht = 0.5 * wavelength * dSpacingi # move reciprocal lattice vectors to sample frame gHat_s = num.dot(rMat_c.squeeze(), gHat_c) if chiTilt is None: cchi = 1. schi = 0. rchi = num.eye(3) else: cchi = num.cos(chiTilt) schi = num.sin(chiTilt) rchi = num.array([[ 1., 0., 0.], [ 0., cchi, -schi], [ 0., schi, cchi]]) pass a = cchi * gHat_s[0, :] b = -cchi * gHat_s[2, :] c = schi * gHat_s[1, :] - sintht # form solution abMag = num.sqrt(a*a + b*b); assert num.all(abMag > 0), "Beam vector specification is infealible!" phaseAng = num.arctan2(b, a) rhs = c / abMag; rhs[abs(rhs) > 1.] = num.nan rhsAng = num.arcsin(rhs) # write ome angle output arrays (NaNs persist here) ome0 = rhsAng - phaseAng ome1 = num.pi - rhsAng - phaseAng goodOnes_s = -num.isnan(ome0) eta0 = num.nan * num.ones_like(ome0) eta1 = num.nan * num.ones_like(ome1) # mark feasible reflections goodOnes = num.tile(goodOnes_s, (1, 2)).flatten() numGood_s = sum(goodOnes_s) numGood = 2 * numGood_s tmp_eta = num.empty(numGood) tmp_gvec = num.tile(gHat_c, (1, 2))[:, goodOnes] allome = num.hstack([ome0, ome1]) for i in range(numGood): come = num.cos(allome[goodOnes][i]) some = num.sin(allome[goodOnes][i]) rome = num.array([[ come, 0., some], [ 0., 1., 0.], [-some, 0., come]]) rMat_s = num.dot(rchi, rome) gVec_l = num.dot(rMat_s, num.dot(rMat_c, tmp_gvec[:, i].reshape(3, 1) ) ) tmp_eta[i] = num.arctan2(gVec_l[1], gVec_l[0]) pass eta0[goodOnes_s] = tmp_eta[:numGood_s] eta1[goodOnes_s] = tmp_eta[numGood_s:] # make assoc tTh array tTh = 2.*num.arcsin(sintht).flatten() tTh0 = tTh; tTh0[-goodOnes_s] = num.nan gVec_s = num.tile(dSpacingi, (3, 1)) * gHat_s oangs0 = num.vstack([tTh0.flatten(), eta0.flatten(), ome0.flatten()]) oangs1 = num.vstack([tTh0.flatten(), eta1.flatten(), ome1.flatten()]) return gVec_s, oangs0, oangs1