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 post_process_stress(grain_data, c_mat_C, schmid_T_list=None): num_grains = grain_data.shape[0] stress_S = np.zeros([num_grains, 6]) stress_C = np.zeros([num_grains, 6]) hydrostatic = np.zeros([num_grains, 1]) pressure = np.zeros([num_grains, 1]) von_mises = np.zeros([num_grains, 1]) if schmid_T_list is not None: num_slip_systems = schmid_T_list.shape[0] RSS = np.zeros([num_grains, num_slip_systems]) for jj in np.arange(num_grains): expMap = np.atleast_2d(grain_data[jj, 3:6]).T strainTmp = np.atleast_2d(grain_data[jj, 15:21]).T #Turn exponential map into an orientation matrix Rsc = rot.rotMatOfExpMap(expMap) strainTenS = np.zeros((3, 3), dtype='float64') strainTenS[0, 0] = strainTmp[0] strainTenS[1, 1] = strainTmp[1] strainTenS[2, 2] = strainTmp[2] strainTenS[1, 2] = strainTmp[3] strainTenS[0, 2] = strainTmp[4] strainTenS[0, 1] = strainTmp[5] strainTenS[2, 1] = strainTmp[3] strainTenS[2, 0] = strainTmp[4] strainTenS[1, 0] = strainTmp[5] strainTenC = np.dot(np.dot(Rsc.T, strainTenS), Rsc) strainVecC = mutil.strainTenToVec(strainTenC) #Calculate stress stressVecC = np.dot(c_mat_C, strainVecC) stressTenC = mutil.stressVecToTen(stressVecC) stressTenS = np.dot(np.dot(Rsc, stressTenC), Rsc.T) stressVecS = mutil.stressTenToVec(stressTenS) #Calculate hydrostatic stress hydrostaticStress = (stressVecS[:3].sum() / 3) #Calculate Von Mises Stress devStressS = stressTenS - hydrostaticStress * np.identity(3) vonMisesStress = np.sqrt((3 / 2) * (devStressS**2).sum()) #Project on to slip systems if schmid_T_list is not None: for ii in np.arange(num_slip_systems): RSS[jj, ii] = np.abs( (stressTenC * schmid_T_list[ii, :, :]).sum()) stress_S[jj, :] = stressVecS.flatten() stress_C[jj, :] = stressVecC.flatten() hydrostatic[jj, 0] = hydrostaticStress pressure[jj, 0] = -hydrostaticStress von_mises[jj, 0] = vonMisesStress stress_data = dict() stress_data['stress_S'] = stress_S stress_data['stress_C'] = stress_C stress_data['hydrostatic'] = hydrostatic stress_data['pressure'] = pressure stress_data['von_mises'] = von_mises if schmid_T_list is not None: stress_data['RSS'] = RSS return stress_data
quats_final = rot.quatOfExpMap( (grain_data['scan%d' % no_load_scans[-1]][:, 3:6].T)) expmaps_final = grain_data['scan111'][:, 3:6].T grainlist = [] for i in range(ngrains): mis = rot.misorientation(quats_init[:, i:i + 1], quats_final[:, i:i + 1], (crystal_symmetry, ))[0] mis_deg = np.degrees(mis) if mis_deg > 0.05: grainlist.append(i) #%% rmats_init = rot.rotMatOfExpMap(np.array(expmaps_init)[:, grainlist]) rmats_final = rot.rotMatOfExpMap(np.array(expmaps_final)[:, grainlist]) # getting symmetry group directly here; could also grab from planeData object # qsym = symm.quatOfLaueGroup('d6h') plane_data = load_pdata( '/Users/rachellim/Documents/Research/CHESS_Jun17/2020-08-03/materials2.hexrd', 'ti7al') qsym = plane_data.getQSym() bmat = plane_data.latVecOps['B'] # this was for 001 triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3))).T) # this if for the standard triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3)))) sst_vertices = mutil.unitVector(
def getFriedelPair(tth0, eta0, *ome0, **kwargs): """ Get the diffractometer angular coordinates in degrees for the Friedel pair of a given reflection (min angular distance). AUTHORS: J. V. Bernier -- 10 Nov 2009 USAGE: ome1, eta1 = getFriedelPair(tth0, eta0, *ome0, display=False, units='degrees', convention='hexrd') INPUTS: 1) tth0 is a list (or ndarray) of 1 or n the bragg angles (2theta) for the n reflections (tiled to match eta0 if only 1 is given). 2) eta0 is a list (or ndarray) of 1 or n azimuthal coordinates for the n reflections (tiled to match tth0 if only 1 is given). 3) ome0 is a list (or ndarray) of 1 or n reference oscillation angles for the n reflections (denoted omega in [1]). This argument is optional. 4) Keyword arguments may be one of the following: Keyword Values|{default} Action -------------- -------------- -------------- 'display' True|{False} toggles display info to cmd line 'units' 'radians'|{'degrees'} sets units for input angles 'convention' 'fable'|{'hexrd'} sets conventions defining the angles (see below) 'chiTilt' None the inclination (about Xlab) of the oscillation axis OUTPUTS: 1) ome1 contains the oscialltion angle coordinates of the Friedel pairs associated with the n input reflections, relative to ome0 (i.e. ome1 = <result> + ome0). Output is in DEGREES! 2) eta1 contains the azimuthal coordinates of the Friedel pairs associated with the n input reflections. Output units are controlled via the module variable 'outputDegrees' NOTES: JVB) The ouputs ome1, eta1 are written using the selected convention, but the units are alway degrees. May change this to work with Nathan's global... JVB) In the 'fable' convention [1], {XYZ} form a RHON basis where X is downstream, Z is vertical, and eta is CCW with +Z defining eta = 0. JVB) In the 'hexrd' convention [2], {XYZ} form a RHON basis where Z is upstream, Y is vertical, and eta is CCW with +X defining eta = 0. REFERENCES: [1] E. M. Lauridsen, S. Schmidt, R. M. Suter, and H. F. Poulsen, ``Tracking: a method for structural characterization of grains in powders or polycrystals''. J. Appl. Cryst. (2001). 34, 744--750 [2] J. V. Bernier, M. P. Miller, J. -S. Park, and U. Lienert, ``Quantitative Stress Analysis of Recrystallized OFHC Cu Subject to Deformed In Situ'', J. Eng. Mater. Technol. (2008). 130. DOI:10.1115/1.2870234 """ dispFlag = False fableFlag = False chi = None c1 = 1.0 c2 = pi / 180.0 zTol = 1.0e-7 # cast to arrays (in case they aren't) if num.isscalar(eta0): eta0 = [eta0] if num.isscalar(tth0): tth0 = [tth0] if num.isscalar(ome0): ome0 = [ome0] eta0 = num.asarray(eta0) tth0 = num.asarray(tth0) ome0 = num.asarray(ome0) if eta0.ndim != 1: raise RuntimeError, "your azimuthal input was not 1-D, so I do not know what you expect me to do" npts = len(eta0) if tth0.ndim != 1: raise RuntimeError, "your Bragg angle input was not 1-D, so I do not know what you expect me to do" else: if len(tth0) != npts: if len(tth0) == 1: tth0 = tth0 * num.ones(npts) elif npts == 1: npts = len(tth0) eta0 = eta0 * num.ones(npts) else: raise RuntimeError, "the azimuthal and Bragg angle inputs are inconsistent" if len(ome0) == 0: ome0 = num.zeros(npts) # dummy ome0 elif len(ome0) == 1 and npts > 1: ome0 = ome0 * num.ones(npts) else: if len(ome0) != npts: raise RuntimeError( "your oscialltion angle input is inconsistent; " + "it has length %d while it should be %d" % (len(ome0), npts) ) # keyword args processing kwarglen = len(kwargs) if kwarglen > 0: argkeys = kwargs.keys() for i in range(kwarglen): if argkeys[i] == "display": dispFlag = kwargs[argkeys[i]] elif argkeys[i] == "convention": if kwargs[argkeys[i]].lower() == "fable": fableFlag = True elif argkeys[i] == "units": if kwargs[argkeys[i]] == "radians": c1 = 180.0 / pi c2 = 1.0 elif argkeys[i] == "chiTilt": if kwargs[argkeys[i]] is not None: chi = kwargs[argkeys[i]] # a little talkback... if dispFlag: if fableFlag: print "\nUsing Fable angle convention\n" else: print "\nUsing image-based angle convention\n" # mapped eta input # - in DEGREES, thanks to c1 eta0 = mapAngle(c1 * eta0, [-180, 180], units="degrees") if fableFlag: eta0 = 90 - eta0 # must put args into RADIANS # - eta0 is in DEGREES, # - the others are in whatever was entered, hence c2 eta0 = d2r * eta0 tht0 = c2 * tth0 / 2 if chi is not None: chi = c2 * chi else: chi = 0 # --------------------- # SYSTEM SOLVE # # # cos(chi)cos(eta)cos(theta)sin(x) - cos(chi)sin(theta)cos(x) = sin(theta) - sin(chi)sin(eta)cos(theta) # # # Identity: a sin x + b cos x = sqrt(a**2 + b**2) sin (x + alfa) # # / # | atan(b/a) for a > 0 # alfa < # | pi + atan(b/a) for a < 0 # \ # # => sin (x + alfa) = c / sqrt(a**2 + b**2) # # must use both branches for sin(x) = n: x = u (+ 2k*pi) | x = pi - u (+ 2k*pi) # cchi = num.cos(chi) schi = num.sin(chi) ceta = num.cos(eta0) seta = num.sin(eta0) ctht = num.cos(tht0) stht = num.sin(tht0) nchi = num.c_[0.0, cchi, schi].T gHat0_l = -num.vstack([ceta * ctht, seta * ctht, stht]) a = cchi * ceta * ctht b = -cchi * stht c = stht + schi * seta * ctht # form solution abMag = num.sqrt(a * a + b * b) assert num.all(abMag > 0), "Beam vector specification is infeasible!" phaseAng = num.arctan2(b, a) rhs = c / abMag rhs[abs(rhs) > 1.0] = num.nan rhsAng = num.arcsin(rhs) # write ome angle output arrays (NaNs persist here) ome1 = rhsAng - phaseAng ome2 = num.pi - rhsAng - phaseAng ome1 = mapAngle(ome1, [-num.pi, num.pi], units="radians") ome2 = mapAngle(ome2, [-num.pi, num.pi], units="radians") ome_stack = num.vstack([ome1, ome2]) min_idx = num.argmin(abs(ome_stack), axis=0) ome_min = ome_stack[min_idx, range(len(ome1))] eta_min = num.nan * num.ones_like(ome_min) # mark feasible reflections goodOnes = -num.isnan(ome_min) numGood = sum(goodOnes) tmp_eta = num.empty(numGood) tmp_gvec = gHat0_l[:, goodOnes] for i in range(numGood): come = num.cos(ome_min[goodOnes][i]) some = num.sin(ome_min[goodOnes][i]) rchi = rotMatOfExpMap(num.tile(ome_min[goodOnes][i], (3, 1)) * nchi) gHat_l = num.dot(rchi, tmp_gvec[:, i].reshape(3, 1)) tmp_eta[i] = num.arctan2(gHat_l[1], gHat_l[0]) pass eta_min[goodOnes] = tmp_eta # everybody back to DEGREES! # - ome1 is in RADIANS here # - convert and put into [-180, 180] ome1 = mapAngle(mapAngle(r2d * ome_min, [-180, 180], units="degrees") + c1 * ome0, [-180, 180], units="degrees") # put eta1 in [-180, 180] eta1 = mapAngle(r2d * eta_min, [-180, 180], units="degrees") if not outputDegrees: ome1 = d2r * ome1 eta1 = d2r * eta1 return ome1, eta1
from hexrd.xrd import transforms as xf from hexrd.xrd import transforms_CAPI as xfcapi if xrdbase.haveMultiProc: multiprocessing = xrdbase.multiprocessing # formerly import # module vars piby2 = num.pi * 0.5 r2d = 180. / num.pi d2r = num.pi / 180. Xl = num.c_[1, 0, 0].T Yl = num.c_[0, 1, 0].T Zl = num.c_[0, 0, 1].T fableSampCOB = num.dot( rotMatOfExpMap(piby2*Zl), rotMatOfExpMap(piby2*Yl) ) # global vars for multiproc paintGrid method planeData_MP = None omeMin_MP = None omeMax_MP = None etaMin_MP = None etaMax_MP = None hklList_MP = None hklIDs_MP = None etaOmeMaps_MP = None bMat_MP = None threshold_MP = None class GrainSpotter:
from hexrd.xrd.symmetry import toFundamentalRegion from hexrd.xrd import xrdbase if xrdbase.haveMultiProc: multiprocessing = xrdbase.multiprocessing # formerly import # module vars piby2 = num.pi * 0.5 r2d = 180. / num.pi d2r = num.pi / 180. Xl = num.c_[1, 0, 0].T Yl = num.c_[0, 1, 0].T Zl = num.c_[0, 0, 1].T fableSampCOB = num.dot(rotMatOfExpMap(piby2 * Zl), rotMatOfExpMap(piby2 * Yl)) # global vars for multiproc paintGrid method planeData_MP = None omeMin_MP = None omeMax_MP = None etaMin_MP = None etaMax_MP = None hklList_MP = None hklIDs_MP = None etaOmeMaps_MP = None bMat_MP = None threshold_MP = None class GrainSpotter:
from hexrd import matrixutil as mutil from hexrd.xrd import rotations as rot from hexrd.xrd.transforms import detectorXYToGvec d2r = np.pi / 180. r2d = 180. / np.pi Xl = np.c_[1, 0, 0].T Yl = np.c_[0, 1, 0].T Zl = np.c_[0, 0, 1].T eVec = Xl.flatten() chi_b = 15 ome_b = 5 rMat_b = np.dot(rot.rotMatOfExpMap(d2r * chi_b * Xl), rot.rotMatOfExpMap(d2r * ome_b * Yl)) bVec = np.dot(rMat_b, -Zl) beam_len = 10 tVec_d = np.c_[-5.0, 3.0, -10.0].T tVec_s = np.c_[3.0, 0.2, -1.5].T tVec_c = np.c_[2.0, 0.8, -0.7].T rMat_d = rot.rotMatOfExpMap(d2r * 21 * mutil.unitVector(np.c_[2, 3, 1].T)) chi = 21 * d2r ome = 67 * d2r rMat_s = np.dot(rot.rotMatOfExpMap(chi * Xl), rot.rotMatOfExpMap(ome * Yl)) rMat_c = rot.rotMatOfExpMap(d2r * 36 * mutil.unitVector(np.c_[1, 2, 3].T))
def gen_trial_exp_data(grain_out_file,det_file,mat_file, x_ray_energy, mat_name, max_tth, comp_thresh, chi2_thresh, misorientation_bnd, \ misorientation_spacing,ome_range_deg, nframes, beam_stop_width): print('Loading Grain Data.....') #gen_grain_data ff_data = np.loadtxt(grain_out_file) #ff_data=np.atleast_2d(ff_data[2,:]) exp_maps = ff_data[:, 3:6] t_vec_ds = ff_data[:, 6:9] # completeness = ff_data[:, 1] chi2 = ff_data[:, 2] n_grains = exp_maps.shape[0] rMat_c = rot.rotMatOfExpMap(exp_maps.T) cut = np.where( np.logical_and(completeness > comp_thresh, chi2 < chi2_thresh))[0] exp_maps = exp_maps[cut, :] t_vec_ds = t_vec_ds[cut, :] chi2 = chi2[cut] # Add Misorientation mis_amt = misorientation_bnd * np.pi / 180. spacing = misorientation_spacing * np.pi / 180. mis_steps = int(misorientation_bnd / misorientation_spacing) ori_pts = np.arange(-mis_amt, (mis_amt + (spacing * 0.999)), spacing) num_ori_grid_pts = ori_pts.shape[0]**3 num_oris = exp_maps.shape[0] XsO, YsO, ZsO = np.meshgrid(ori_pts, ori_pts, ori_pts) grid0 = np.vstack([XsO.flatten(), YsO.flatten(), ZsO.flatten()]).T exp_maps_expanded = np.zeros([num_ori_grid_pts * num_oris, 3]) t_vec_ds_expanded = np.zeros([num_ori_grid_pts * num_oris, 3]) for ii in np.arange(num_oris): pts_to_use = np.arange(num_ori_grid_pts) + ii * num_ori_grid_pts exp_maps_expanded[pts_to_use, :] = grid0 + np.r_[exp_maps[ii, :]] t_vec_ds_expanded[pts_to_use, :] = np.r_[t_vec_ds[ii, :]] exp_maps = exp_maps_expanded t_vec_ds = t_vec_ds_expanded n_grains = exp_maps.shape[0] rMat_c = rot.rotMatOfExpMap(exp_maps.T) print('Loading Instrument Data.....') instr_cfg = yaml.load(open(det_file, 'r')) tiltAngles = instr_cfg['detector']['transform']['tilt_angles'] tVec_d = np.array(instr_cfg['detector']['transform']['t_vec_d']).reshape( 3, 1) #tVec_d[0] = -0.05 chi = instr_cfg['oscillation_stage']['chi'] tVec_s = np.array(instr_cfg['oscillation_stage']['t_vec_s']).reshape(3, 1) rMat_d = makeDetectorRotMat(tiltAngles) rMat_s = makeOscillRotMat([chi, 0.]) pixel_size = instr_cfg['detector']['pixels']['size'] nrows = instr_cfg['detector']['pixels']['rows'] ncols = instr_cfg['detector']['pixels']['columns'] # row_dim = pixel_size[0]*nrows # in mm # col_dim = pixel_size[1]*ncols # in mm x_col_edges = pixel_size[1] * (np.arange(ncols + 1) - 0.5 * ncols) y_row_edges = pixel_size[0] * (np.arange(nrows + 1) - 0.5 * nrows)[::-1] panel_dims = [(-0.5 * ncols * pixel_size[1], -0.5 * nrows * pixel_size[0]), (0.5 * ncols * pixel_size[1], 0.5 * nrows * pixel_size[0])] # a bit overkill, but grab max two-theta from all pixel transforms rx, ry = np.meshgrid(x_col_edges, y_row_edges) gcrds = detectorXYToGvec( np.vstack([rx.flatten(), ry.flatten()]).T, rMat_d, rMat_s, tVec_d, tVec_s, np.zeros(3)) pixel_tth = gcrds[0][0] detector_params = np.hstack( [tiltAngles, tVec_d.flatten(), chi, tVec_s.flatten()]) ome_period_deg = (ome_range_deg[0][0], (ome_range_deg[0][0] + 360.) ) #degrees ome_step_deg = (ome_range_deg[0][1] - ome_range_deg[0][0]) / nframes #degrees ome_period = (ome_period_deg[0] * np.pi / 180., ome_period_deg[1] * np.pi / 180.) ome_range = [(ome_range_deg[0][0] * np.pi / 180., ome_range_deg[0][1] * np.pi / 180.)] ome_step = ome_step_deg * np.pi / 180. ome_edges = np.arange(nframes + 1) * ome_step + ome_range[0][0] #fixed 2/26/17 base = np.array([x_col_edges[0], y_row_edges[0], ome_edges[0]]) deltas = np.array([ x_col_edges[1] - x_col_edges[0], y_row_edges[1] - y_row_edges[0], ome_edges[1] - ome_edges[0] ]) inv_deltas = 1.0 / deltas clip_vals = np.array([ncols, nrows]) print('Loading Material Data.....') #Load Material Data materials = cpl.load(open(mat_file, "rb")) check = np.zeros(len(materials)) for ii in np.arange(len(materials)): #print materials[ii].name check[ii] = materials[ii].name == mat_name mat_used = materials[np.where(check)[0][0]] #niti_mart.beamEnergy = valunits.valWUnit("wavelength","ENERGY",61.332,"keV") mat_used.beamEnergy = valunits.valWUnit("wavelength", "ENERGY", x_ray_energy, "keV") mat_used.planeData.exclusions = np.zeros(len( mat_used.planeData.exclusions), dtype=bool) if max_tth > 0.: mat_used.planeData.tThMax = np.amax(np.radians(max_tth)) else: mat_used.planeData.tThMax = np.amax(pixel_tth) pd = mat_used.planeData print('Final Assembly.....') experiment = argparse.Namespace() # grains related information experiment.n_grains = n_grains # this can be derived from other values... experiment.rMat_c = rMat_c # n_grains rotation matrices (one per grain) experiment.exp_maps = exp_maps # n_grains exp_maps -angle * rotation axis- (one per grain) experiment.plane_data = pd experiment.detector_params = detector_params experiment.pixel_size = pixel_size experiment.ome_range = ome_range experiment.ome_period = ome_period experiment.x_col_edges = x_col_edges experiment.y_row_edges = y_row_edges experiment.ome_edges = ome_edges experiment.ncols = ncols experiment.nrows = nrows experiment.nframes = nframes # used only in simulate... experiment.rMat_d = rMat_d experiment.tVec_d = np.atleast_2d(detector_params[3:6]).T experiment.chi = detector_params[ 6] # note this is used to compute S... why is it needed? experiment.tVec_s = np.atleast_2d(detector_params[7:]).T experiment.rMat_c = rMat_c experiment.distortion = None experiment.panel_dims = panel_dims # used only in simulate... experiment.base = base experiment.inv_deltas = inv_deltas experiment.clip_vals = clip_vals experiment.bsw = beam_stop_width if mis_steps == 0: nf_to_ff_id_map = cut else: nf_to_ff_id_map = np.tile(cut, 27 * mis_steps) return experiment, nf_to_ff_id_map
def getFriedelPair(tth0, eta0, *ome0, **kwargs): """ Get the diffractometer angular coordinates in degrees for the Friedel pair of a given reflection (min angular distance). AUTHORS: J. V. Bernier -- 10 Nov 2009 USAGE: ome1, eta1 = getFriedelPair(tth0, eta0, *ome0, display=False, units='degrees', convention='hexrd') INPUTS: 1) tth0 is a list (or ndarray) of 1 or n the bragg angles (2theta) for the n reflections (tiled to match eta0 if only 1 is given). 2) eta0 is a list (or ndarray) of 1 or n azimuthal coordinates for the n reflections (tiled to match tth0 if only 1 is given). 3) ome0 is a list (or ndarray) of 1 or n reference oscillation angles for the n reflections (denoted omega in [1]). This argument is optional. 4) Keyword arguments may be one of the following: Keyword Values|{default} Action -------------- -------------- -------------- 'display' True|{False} toggles display info to cmd line 'units' 'radians'|{'degrees'} sets units for input angles 'convention' 'fable'|{'hexrd'} sets conventions defining the angles (see below) 'chiTilt' None the inclination (about Xlab) of the oscillation axis OUTPUTS: 1) ome1 contains the oscialltion angle coordinates of the Friedel pairs associated with the n input reflections, relative to ome0 (i.e. ome1 = <result> + ome0). Output is in DEGREES! 2) eta1 contains the azimuthal coordinates of the Friedel pairs associated with the n input reflections. Output units are controlled via the module variable 'outputDegrees' NOTES: JVB) The ouputs ome1, eta1 are written using the selected convention, but the units are alway degrees. May change this to work with Nathan's global... JVB) In the 'fable' convention [1], {XYZ} form a RHON basis where X is downstream, Z is vertical, and eta is CCW with +Z defining eta = 0. JVB) In the 'hexrd' convention [2], {XYZ} form a RHON basis where Z is upstream, Y is vertical, and eta is CCW with +X defining eta = 0. REFERENCES: [1] E. M. Lauridsen, S. Schmidt, R. M. Suter, and H. F. Poulsen, ``Tracking: a method for structural characterization of grains in powders or polycrystals''. J. Appl. Cryst. (2001). 34, 744--750 [2] J. V. Bernier, M. P. Miller, J. -S. Park, and U. Lienert, ``Quantitative Stress Analysis of Recrystallized OFHC Cu Subject to Deformed In Situ'', J. Eng. Mater. Technol. (2008). 130. DOI:10.1115/1.2870234 """ dispFlag = False fableFlag = False chi = None c1 = 1. c2 = pi/180. zTol = 1.e-7 # cast to arrays (in case they aren't) if num.isscalar(eta0): eta0 = [eta0] if num.isscalar(tth0): tth0 = [tth0] if num.isscalar(ome0): ome0 = [ome0] eta0 = num.asarray(eta0) tth0 = num.asarray(tth0) ome0 = num.asarray(ome0) if eta0.ndim != 1: raise RuntimeError, 'your azimuthal input was not 1-D, so I do not know what you expect me to do' npts = len(eta0) if tth0.ndim != 1: raise RuntimeError, 'your Bragg angle input was not 1-D, so I do not know what you expect me to do' else: if len(tth0) != npts: if len(tth0) == 1: tth0 = tth0*num.ones(npts) elif npts == 1: npts = len(tth0) eta0 = eta0*num.ones(npts) else: raise RuntimeError, 'the azimuthal and Bragg angle inputs are inconsistent' if len(ome0) == 0: ome0 = num.zeros(npts) # dummy ome0 elif len(ome0) == 1 and npts > 1: ome0 = ome0*num.ones(npts) else: if len(ome0) != npts: raise RuntimeError('your oscialltion angle input is inconsistent; ' \ + 'it has length %d while it should be %d' % (len(ome0), npts) ) # keyword args processing kwarglen = len(kwargs) if kwarglen > 0: argkeys = kwargs.keys() for i in range(kwarglen): if argkeys[i] == 'display': dispFlag = kwargs[argkeys[i]] elif argkeys[i] == 'convention': if kwargs[argkeys[i]].lower() == 'fable': fableFlag = True elif argkeys[i] == 'units': if kwargs[argkeys[i]] == 'radians': c1 = 180./pi c2 = 1. elif argkeys[i] == 'chiTilt': if kwargs[argkeys[i]] is not None: chi = kwargs[argkeys[i]] # a little talkback... if dispFlag: if fableFlag: print '\nUsing Fable angle convention\n' else: print '\nUsing image-based angle convention\n' # mapped eta input # - in DEGREES, thanks to c1 eta0 = mapAngle(c1*eta0, [-180, 180], units='degrees') if fableFlag: eta0 = 90 - eta0 # must put args into RADIANS # - eta0 is in DEGREES, # - the others are in whatever was entered, hence c2 eta0 = d2r*eta0 tht0 = c2*tth0/2 if chi is not None: chi = c2*chi else: chi = 0 # --------------------- # SYSTEM SOLVE # # # cos(chi)cos(eta)cos(theta)sin(x) - cos(chi)sin(theta)cos(x) = sin(theta) - sin(chi)sin(eta)cos(theta) # # # Identity: a sin x + b cos x = sqrt(a**2 + b**2) sin (x + alfa) # # / # | atan(b/a) for a > 0 # alfa < # | pi + atan(b/a) for a < 0 # \ # # => sin (x + alfa) = c / sqrt(a**2 + b**2) # # must use both branches for sin(x) = n: x = u (+ 2k*pi) | x = pi - u (+ 2k*pi) # cchi = num.cos(chi); schi = num.sin(chi) ceta = num.cos(eta0); seta = num.sin(eta0) ctht = num.cos(tht0); stht = num.sin(tht0) nchi = num.c_[0., cchi, schi].T gHat0_l = num.vstack([ceta * ctht, seta * ctht, stht]) a = cchi*ceta*ctht b = cchi*schi*seta*ctht + schi*schi*stht - stht c = stht + cchi*schi*seta*ctht + schi*schi*stht # 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) ome1 = rhsAng - phaseAng ome2 = num.pi - rhsAng - phaseAng ome1 = mapAngle(ome1, [-num.pi, num.pi], units='radians') ome2 = mapAngle(ome2, [-num.pi, num.pi], units='radians') ome_stack = num.vstack([ome1, ome2]) min_idx = num.argmin(abs(ome_stack), axis=0) ome_min = ome_stack[min_idx, range(len(ome1))] eta_min = num.nan * num.ones_like(ome_min) # mark feasible reflections goodOnes = -num.isnan(ome_min) numGood = sum(goodOnes) tmp_eta = num.empty(numGood) tmp_gvec = gHat0_l[:, goodOnes] for i in range(numGood): come = num.cos(ome_min[goodOnes][i]) some = num.sin(ome_min[goodOnes][i]) rchi = rotMatOfExpMap( num.tile(ome_min[goodOnes][i], (3, 1)) * nchi ) gHat_l = num.dot(rchi, tmp_gvec[:, i].reshape(3, 1)) tmp_eta[i] = num.arctan2(gHat_l[1], gHat_l[0]) pass eta_min[goodOnes] = tmp_eta # everybody back to DEGREES! # - ome1 is in RADIANS here # - convert and put into [-180, 180] ome1 = mapAngle( mapAngle(r2d*ome_min, [-180, 180], units='degrees') + c1*ome0, [-180, 180], units='degrees') # put eta1 in [-180, 180] eta1 = mapAngle(r2d*eta_min, [-180, 180], units='degrees') if not outputDegrees: ome1 = d2r * ome1 eta1 = d2r * eta1 return ome1, eta1
def post_process_stress(grain_data,c_mat_C,schmid_T_list=None): num_grains=grain_data.shape[0] stress_S=np.zeros([num_grains,6]) stress_C=np.zeros([num_grains,6]) hydrostatic=np.zeros([num_grains,1]) pressure=np.zeros([num_grains,1]) von_mises=np.zeros([num_grains,1]) if schmid_T_list is not None: num_slip_systems=schmid_T_list.shape[0] RSS=np.zeros([num_grains,num_slip_systems]) for jj in np.arange(num_grains): expMap=np.atleast_2d(grain_data[jj,3:6]).T strainTmp=np.atleast_2d(grain_data[jj,15:21]).T #Turn exponential map into an orientation matrix Rsc=rot.rotMatOfExpMap(expMap) strainTenS = np.zeros((3, 3), dtype='float64') strainTenS[0, 0] = strainTmp[0] strainTenS[1, 1] = strainTmp[1] strainTenS[2, 2] = strainTmp[2] strainTenS[1, 2] = strainTmp[3] strainTenS[0, 2] = strainTmp[4] strainTenS[0, 1] = strainTmp[5] strainTenS[2, 1] = strainTmp[3] strainTenS[2, 0] = strainTmp[4] strainTenS[1, 0] = strainTmp[5] strainTenC=np.dot(np.dot(Rsc.T,strainTenS),Rsc) strainVecC = mutil.strainTenToVec(strainTenC) #Calculate stress stressVecC=np.dot(c_mat_C,strainVecC) stressTenC = mutil.stressVecToTen(stressVecC) stressTenS = np.dot(np.dot(Rsc,stressTenC),Rsc.T) stressVecS = mutil.stressTenToVec(stressTenS) #Calculate hydrostatic stress hydrostaticStress=(stressVecS[:3].sum()/3) #Calculate Von Mises Stress devStressS=stressTenS-hydrostaticStress*np.identity(3) vonMisesStress=np.sqrt((3/2)*(devStressS**2).sum()) #Project on to slip systems if schmid_T_list is not None: for ii in np.arange(num_slip_systems): RSS[jj,ii]=np.abs((stressTenC*schmid_T_list[ii,:,:]).sum()) stress_S[jj,:]=stressVecS.flatten() stress_C[jj,:]=stressVecC.flatten() hydrostatic[jj,0]=hydrostaticStress pressure[jj,0]=-hydrostaticStress von_mises[jj,0]=vonMisesStress stress_data=dict() stress_data['stress_S']=stress_S stress_data['stress_C']=stress_C stress_data['hydrostatic']=hydrostatic stress_data['pressure']=pressure stress_data['von_mises']=von_mises if schmid_T_list is not None: stress_data['RSS']=RSS return stress_data
def gen_trial_exp_data(grain_out_file,det_file,mat_file, x_ray_energy, mat_name, max_tth, comp_thresh, chi2_thresh, misorientation_bnd, \ misorientation_spacing,ome_range_deg, nframes, beam_stop_width): print('Loading Grain Data.....') #gen_grain_data ff_data=np.loadtxt(grain_out_file) #ff_data=np.atleast_2d(ff_data[2,:]) exp_maps=ff_data[:,3:6] t_vec_ds=ff_data[:,6:9] # completeness=ff_data[:,1] chi2=ff_data[:,2] n_grains=exp_maps.shape[0] rMat_c = rot.rotMatOfExpMap(exp_maps.T) cut=np.where(np.logical_and(completeness>comp_thresh,chi2<chi2_thresh))[0] exp_maps=exp_maps[cut,:] t_vec_ds=t_vec_ds[cut,:] chi2=chi2[cut] # Add Misorientation mis_amt=misorientation_bnd*np.pi/180. spacing=misorientation_spacing*np.pi/180. ori_pts = np.arange(-mis_amt, (mis_amt+(spacing*0.999)),spacing) num_ori_grid_pts=ori_pts.shape[0]**3 num_oris=exp_maps.shape[0] XsO, YsO, ZsO = np.meshgrid(ori_pts, ori_pts, ori_pts) grid0 = np.vstack([XsO.flatten(), YsO.flatten(), ZsO.flatten()]).T exp_maps_expanded=np.zeros([num_ori_grid_pts*num_oris,3]) t_vec_ds_expanded=np.zeros([num_ori_grid_pts*num_oris,3]) for ii in np.arange(num_oris): pts_to_use=np.arange(num_ori_grid_pts)+ii*num_ori_grid_pts exp_maps_expanded[pts_to_use,:]=grid0+np.r_[exp_maps[ii,:] ] t_vec_ds_expanded[pts_to_use,:]=np.r_[t_vec_ds[ii,:] ] exp_maps=exp_maps_expanded t_vec_ds=t_vec_ds_expanded n_grains=exp_maps.shape[0] rMat_c = rot.rotMatOfExpMap(exp_maps.T) print('Loading Instrument Data.....') instr_cfg = yaml.load(open(det_file, 'r')) tiltAngles = instr_cfg['detector']['transform']['tilt_angles'] tVec_d = np.array(instr_cfg['detector']['transform']['t_vec_d']).reshape(3, 1) #tVec_d[0] = -0.05 chi = instr_cfg['oscillation_stage']['chi'] tVec_s = np.array(instr_cfg['oscillation_stage']['t_vec_s']).reshape(3, 1) rMat_d = makeDetectorRotMat(tiltAngles) rMat_s = makeOscillRotMat([chi, 0.]) pixel_size = instr_cfg['detector']['pixels']['size'] nrows = instr_cfg['detector']['pixels']['rows'] ncols = instr_cfg['detector']['pixels']['columns'] # row_dim = pixel_size[0]*nrows # in mm # col_dim = pixel_size[1]*ncols # in mm x_col_edges = pixel_size[1]*(np.arange(ncols+1) - 0.5*ncols) y_row_edges = pixel_size[0]*(np.arange(nrows+1) - 0.5*nrows)[::-1] panel_dims = [(-0.5*ncols*pixel_size[1], -0.5*nrows*pixel_size[0]), ( 0.5*ncols*pixel_size[1], 0.5*nrows*pixel_size[0])] # a bit overkill, but grab max two-theta from all pixel transforms rx, ry = np.meshgrid(x_col_edges, y_row_edges) gcrds = detectorXYToGvec(np.vstack([rx.flatten(), ry.flatten()]).T, rMat_d, rMat_s, tVec_d, tVec_s, np.zeros(3)) pixel_tth = gcrds[0][0] detector_params = np.hstack([tiltAngles, tVec_d.flatten(), chi, tVec_s.flatten()]) ome_period_deg=(ome_range_deg[0][0], (ome_range_deg[0][0]+360.)) #degrees ome_step_deg=(ome_range_deg[0][1]-ome_range_deg[0][0])/nframes #degrees ome_period = (ome_period_deg[0]*np.pi/180.,ome_period_deg[1]*np.pi/180.) ome_range = [(ome_range_deg[0][0]*np.pi/180.,ome_range_deg[0][1]*np.pi/180.)] ome_step = ome_step_deg*np.pi/180. ome_edges = np.arange(nframes+1)*ome_step+ome_range[0][0]#fixed 2/26/17 base = np.array([x_col_edges[0], y_row_edges[0], ome_edges[0]]) deltas = np.array([x_col_edges[1] - x_col_edges[0], y_row_edges[1] - y_row_edges[0], ome_edges[1] - ome_edges[0]]) inv_deltas = 1.0/deltas clip_vals = np.array([ncols, nrows]) print('Loading Material Data.....') #Load Material Data materials=cpl.load(open( mat_file, "rb" )) check=np.zeros(len(materials)) for ii in np.arange(len(materials)): #print materials[ii].name check[ii]=materials[ii].name==mat_name mat_used=materials[np.where(check)[0][0]] #niti_mart.beamEnergy = valunits.valWUnit("wavelength","ENERGY",61.332,"keV") mat_used.beamEnergy = valunits.valWUnit("wavelength","ENERGY",x_ray_energy,"keV") mat_used.planeData.exclusions = np.zeros(len(mat_used.planeData.exclusions), dtype=bool) if max_tth>0.: mat_used.planeData.tThMax = np.amax(np.radians(max_tth)) else: mat_used.planeData.tThMax = np.amax(pixel_tth) pd=mat_used.planeData print('Final Assembly.....') experiment = argparse.Namespace() # grains related information experiment.n_grains = n_grains # this can be derived from other values... experiment.rMat_c = rMat_c # n_grains rotation matrices (one per grain) experiment.exp_maps = exp_maps # n_grains exp_maps -angle * rotation axis- (one per grain) experiment.plane_data = pd experiment.detector_params = detector_params experiment.pixel_size = pixel_size experiment.ome_range = ome_range experiment.ome_period = ome_period experiment.x_col_edges = x_col_edges experiment.y_row_edges = y_row_edges experiment.ome_edges = ome_edges experiment.ncols = ncols experiment.nrows = nrows experiment.nframes = nframes# used only in simulate... experiment.rMat_d = rMat_d experiment.tVec_d = np.atleast_2d(detector_params[3:6]).T experiment.chi = detector_params[6] # note this is used to compute S... why is it needed? experiment.tVec_s = np.atleast_2d(detector_params[7:]).T experiment.rMat_c = rMat_c experiment.distortion = None experiment.panel_dims = panel_dims # used only in simulate... experiment.base = base experiment.inv_deltas = inv_deltas experiment.clip_vals = clip_vals experiment.bsw = beam_stop_width nf_to_ff_id_map=cut return experiment, nf_to_ff_id_map
Eulers_grain = np.zeros([len(scanIDs), 3]) for i in range(len(scanIDs)): q108 = rot.quatOfExpMap(grain_data['scan%d' % scanIDs[i]][:, 3:6].T) expmaps_grain.append(grain_data['scan%d' % scanIDs[i]][grain, 3:6]) mis = rot.misorientation(quats_init[:, grain:grain + 1], q108[:, grain:grain + 1], (crystal_symmetry, ))[0] mis_ang.append(mis) # rotmats_grain.append(rot.rotMatOfExpMap(grain_data['scan%d'%no_load_scans[i]][grain,3:6].T)) # Eulers_grain[i,:] = rot.angles_from_rmat_zxz(rot.rotMatOfExpMap(expmaps_grain)) mis_ang_deg = np.degrees(np.array(mis_ang)) #%% rmats = rot.rotMatOfExpMap(np.array(expmaps_grain).T) # getting symmetry group directly here; could also grab from planeData object # qsym = symm.quatOfLaueGroup('d6h') plane_data = load_pdata( '/Users/rachellim/Documents/Research/CHESS_Jun17/2020-08-03/materials2.hexrd', 'ti7al') qsym = plane_data.getQSym() bmat = plane_data.latVecOps['B'] # this was for 001 triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3))).T) # this if for the standard triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3)))) sst_vertices = mutil.unitVector( np.dot(bmat,
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) # ============================================================================= # %% TRANSFORM GRAINS.OUT DATA # ============================================================================= gt = np.loadtxt( '/Users/rachellim/Documents/Research/Dye_CHESS_Jan20/fd1-q-1_filtered/filtered_scan_0067_grains.out', ndmin=2) rmats = rot.rotMatOfExpMap(gt[:, 3:6].T) # getting symmetry group directly here; could also grab from planeData object # qsym = symm.quatOfLaueGroup('d6h') plane_data = load_pdata( '/Users/rachellim/Documents/Research/CHESS_Jun17/2020-08-03/materials2.hexrd', 'ti7al') qsym = plane_data.getQSym() bmat = plane_data.latVecOps['B'] # this was for 001 triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3))).T) # this if for the standard triangle # sst_vertices = mutil.unitVector(matfuncs.triu(np.ones((3, 3)))) sst_vertices = mutil.unitVector( np.dot(bmat,
from hexrd import matrixutil as mutil from hexrd.xrd import rotations as rot from hexrd.xrd.transforms import detectorXYToGvec d2r = np.pi / 180. r2d = 180. / np.pi Xl = np.c_[1, 0, 0].T Yl = np.c_[0, 1, 0].T Zl = np.c_[0, 0, 1].T eVec = Xl.flatten() chi_b = 15 ome_b = 5 rMat_b = np.dot(rot.rotMatOfExpMap(d2r * chi_b * Xl), rot.rotMatOfExpMap(d2r * ome_b * Yl)) bVec = np.dot(rMat_b, -Zl) beam_len = 10 tVec_d = np.c_[ -5.0, 3.0, -10.0].T tVec_s = np.c_[ 3.0, 0.2, -1.5].T tVec_c = np.c_[ 2.0, 0.8, -0.7].T rMat_d = rot.rotMatOfExpMap(d2r*21*mutil.unitVector(np.c_[2, 3, 1].T)) chi = 21 * d2r ome = 67 * d2r rMat_s = np.dot(rot.rotMatOfExpMap(chi * Xl), rot.rotMatOfExpMap(ome * Yl))