def __init__(self, data, parent=None): super(FitGrainsResultsDialog, self).__init__() self.ax = None self.cmap = hexrd.ui.constants.DEFAULT_CMAP self.data = data self.data_model = FitGrainsResultsModel(data) self.canvas = None self.fig = None self.scatter_artist = None self.colorbar = None loader = UiLoader() self.ui = loader.load_file('fit_grains_results_dialog.ui', parent) flags = self.ui.windowFlags() self.ui.setWindowFlags(flags | Qt.Tool) self.ui.splitter.setStretchFactor(0, 1) self.ui.splitter.setStretchFactor(1, 10) self.setup_tableview() # Add column for equivalent strain ngrains = self.data.shape[0] eqv_strain = np.zeros(ngrains) for i in range(ngrains): emat = vecMVToSymm(self.data[i, 15:21], scale=False) eqv_strain[i] = 2.*np.sqrt(np.sum(emat*emat))/3. np.append(self.data, eqv_strain) self.setup_gui()
def objFuncSX(pFit, pFull, pFlag, dFunc, dFlag, xyo_det, hkls_idx, bMat, vInv, wavelength, bVec, eVec, omePeriod, simOnly=False, returnScalarValue=returnScalarValue): """ """ npts = len(xyo_det) refineFlag = np.hstack([pFlag, dFlag]) # pFull[refineFlag] = pFit/scl[refineFlag] pFull[refineFlag] = pFit dParams = pFull[-len(dFlag):] xy_unwarped = dFunc(xyo_det[:, :2], dParams) # detector quantities rMat_d = xf.makeDetectorRotMat(pFull[:3]) tVec_d = pFull[3:6].reshape(3, 1) # sample quantities chi = pFull[6] tVec_s = pFull[7:10].reshape(3, 1) # crystal quantities rMat_c = xf.makeRotMatOfExpMap(pFull[10:13]) tVec_c = pFull[13:16].reshape(3, 1) gVec_c = np.dot(bMat, hkls_idx) vMat_s = mutil.vecMVToSymm(vInv) # stretch tensor comp matrix from MV notation in SAMPLE frame gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) # reciprocal lattice vectors in SAMPLE frame gHat_s = mutil.unitVector(gVec_s) # unit reciprocal lattice vectors in SAMPLE frame gHat_c = np.dot(rMat_c.T, gHat_s) # unit reciprocal lattice vectors in CRYSTAL frame match_omes, calc_omes = matchOmegas(xyo_det, hkls_idx, chi, rMat_c, bMat, wavelength, vInv=vInv, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) calc_xy = np.zeros((npts, 2)) for i in range(npts): rMat_s = xfcapi.makeOscillRotMat([chi, calc_omes[i]]) calc_xy[i, :] = xfcapi.gvecToDetectorXY(gHat_c[:, i], rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec).flatten() pass if np.any(np.isnan(calc_xy)): print "infeasible pFull: may want to scale back finite difference step size" # return values if simOnly: retval = np.hstack([calc_xy, calc_omes.reshape(npts, 1)]) else: diff_vecs_xy = calc_xy - xy_unwarped[:, :2] diff_ome = xf.angularDifference( calc_omes, xyo_det[:, 2] ) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1) ]).flatten() if returnScalarValue: retval = sum( retval ) return retval
def converted_data(self): # Perform conversions on the data to the specified types. # For instance, use stress instead of strain if that is set. tensor_type = self.tensor_type data = copy.deepcopy(self.data) if self.cylindrical_reference: for grain in data: x, y, z = grain[COORDS_SLICE] rho = np.sqrt(x**2 + z**2) phi = np.arctan2(z, x) grain[COORDS_SLICE] = (rho, phi, y) if tensor_type == 'stress': for grain in data: # Convert strain to stress # Multiply last three numbers by factor of 2 grain[ELASTIC_OFF_DIAGONAL_SLICE] *= 2 grain[ELASTIC_SLICE] = np.dot(self.compliance, grain[ELASTIC_SLICE]) # Compute the equivalent stress sigma = vecMVToSymm(grain[ELASTIC_SLICE], scale=False) deviator = sigma - (1/3) * np.trace(sigma) * np.identity(3) grain[EQUIVALENT_IND] = 3 * np.sqrt(np.sum(deviator**2)) / 2 # Compute the hydrostatic stress grain[HYDROSTATIC_IND] = 1 / 3 * np.trace(sigma) return data
def loop(self): id, grain_params = self._jobs.get(False) # skips the first loop if have_estimate is True have_estimate = not np.all(grain_params[-9] == [0,0,0,1,1,1,0,0,0]) iterations = (have_estimate, len(self._p['eta_tol'])) for iteration in range(*iterations): self.pull_spots(id, grain_params, iteration) grain_params, compl = self.fit_grains(id, grain_params) if compl == 0: break eMat = logm(np.linalg.inv(vecMVToSymm(grain_params[6:]))) dFunc, dParams = self._p['distortion'] resd = objFuncFitGrain( grain_params[gFlag], grain_params, gFlag, self._p['detector_params'], self._p['xyo_det'], self._p['hkls'], self._p['bMat'], self._p['wlen'], bVec_ref, eta_ref, dFunc, dParams, self._p['omega_period'], simOnly=False ) self._results.append((id, grain_params, compl, eMat, sum(resd**2))) self._jobs.task_done()
def __init__(self, data, material=None, parent=None): super().__init__() if material is None: # Assume the active material is the correct one. # This might not actually be the case, though... material = HexrdConfig().active_material if material: # Warn the user so this is clear. print(f'Assuming material of {material.name} for stress ' 'computations') self.ax = None self.cmap = hexrd.ui.constants.DEFAULT_CMAP self.data = data self.data_model = FitGrainsResultsModel(data) self.material = material self.canvas = None self.fig = None self.scatter_artist = None self.colorbar = None loader = UiLoader() self.ui = loader.load_file('fit_grains_results_dialog.ui', parent) flags = self.ui.windowFlags() self.ui.setWindowFlags(flags | Qt.Tool) self.ui.splitter.setStretchFactor(0, 1) self.ui.splitter.setStretchFactor(1, 10) self.setup_tableview() self.load_cmaps() self.reset_glyph_size(update_plot=False) # Add columns for equivalent strain and hydrostatic strain eqv_strain = np.zeros(self.num_grains) hydrostatic_strain = np.zeros(self.num_grains) for i, grain in enumerate(self.data): epsilon = vecMVToSymm(grain[ELASTIC_SLICE], scale=False) deviator = epsilon - (1/3) * np.trace(epsilon) * np.identity(3) eqv_strain[i] = 2 * np.sqrt(np.sum(deviator**2)) / 3 hydrostatic_strain[i] = 1 / 3 * np.trace(epsilon) self.data = np.hstack((self.data, eqv_strain[:, np.newaxis])) self.data = np.hstack((self.data, hydrostatic_strain[:, np.newaxis])) self.setup_gui()
def converted_data(self): # Perform conversions on the data to the specified types. # For instance, use stress instead of strain if that is set. tensor_type = self.tensor_type data = copy.deepcopy(self.data) if tensor_type == 'stress': for grain in data: # Convert strain to stress # Multiply last three numbers by factor of 2 grain[18:21] *= 2 grain[15:21] = np.dot(self.compliance, grain[15:21]) # Compute the equivalent stress m = vecMVToSymm(grain[15:21], scale=False) grain[21] = 2 * np.sqrt(np.sum(m**2)) / 3 return data
def dump_grain(self, grain_id, completeness, chisq, grain_params): assert len(grain_params) == 12, \ "len(grain_params) must be 12, not %d" % len(grain_params) # extract strain emat = logm(np.linalg.inv(mutil.vecMVToSymm(grain_params[6:]))) evec = mutil.symmToVecMV(emat, scale=False) res = [int(grain_id), completeness, chisq] \ + grain_params.tolist() \ + evec.tolist() output_str = self._delim.join([ self._delim.join(['{:<12d}', '{:<12f}', '{:<12e}']).format(*res[:3]), self._delim.join(np.tile('{:<23.16e}', len(res) - 3)).format(*res[3:]) ]) print(output_str, file=self.fid) return output_str
def __init__(self, data, material=None, parent=None): super().__init__() if material is None: # Assume the active material is the correct one. # This might not actually be the case, though... material = HexrdConfig().active_material if material: # Warn the user so this is clear. print(f'Assuming material of {material.name} for stress ' 'computations') self.ax = None self.cmap = hexrd.ui.constants.DEFAULT_CMAP self.data = data self.data_model = FitGrainsResultsModel(data) self.material = material self.canvas = None self.fig = None self.scatter_artist = None self.colorbar = None loader = UiLoader() self.ui = loader.load_file('fit_grains_results_dialog.ui', parent) flags = self.ui.windowFlags() self.ui.setWindowFlags(flags | Qt.Tool) self.ui.splitter.setStretchFactor(0, 1) self.ui.splitter.setStretchFactor(1, 10) self.setup_tableview() # Add column for equivalent strain eqv_strain = np.zeros(self.num_grains) for i, grain in enumerate(self.data): emat = vecMVToSymm(grain[15:21], scale=False) eqv_strain[i] = 2 * np.sqrt(np.sum(emat**2)) / 3 # Reshape so we can hstack it self.data = np.hstack((self.data, eqv_strain[:, np.newaxis])) self.setup_gui()
def dump_grain(self, grain_id, completeness, chisq, grain_params): assert len(grain_params) == 12, \ "len(grain_params) must be 12, not %d" % len(grain_params) # extract strain emat = logm(np.linalg.inv(mutil.vecMVToSymm(grain_params[6:]))) evec = mutil.symmToVecMV(emat, scale=False) res = [int(grain_id), completeness, chisq] \ + grain_params.tolist() \ + evec.tolist() output_str = self._delim.join( [self._delim.join( ['{:<12d}', '{:<12f}', '{:<12e}'] ).format(*res[:3]), self._delim.join( np.tile('{:<23.16e}', len(res) - 3) ).format(*res[3:])] ) print(output_str, file=self.fid) return output_str
def __init__(self, filename, instr_cfg, grain_params, use_attr=False): if isinstance(filename, h5py.File): self.fid = filename else: self.fid = h5py.File(filename + ".hdf5", "w") icfg = {} icfg.update(instr_cfg) # add instrument groups and attributes self.instr_grp = self.fid.create_group('instrument') unwrap_dict_to_h5(self.instr_grp, icfg, asattr=use_attr) # add grain group self.grain_grp = self.fid.create_group('grain') rmat_c = makeRotMatOfExpMap(grain_params[:3]) tvec_c = np.array(grain_params[3:6]).flatten() vinv_s = np.array(grain_params[6:]).flatten() vmat_s = np.linalg.inv(mutil.vecMVToSymm(vinv_s)) if use_attr: # attribute version self.grain_grp.attrs.create('rmat_c', rmat_c) self.grain_grp.attrs.create('tvec_c', tvec_c) self.grain_grp.attrs.create('inv(V)_s', vinv_s) self.grain_grp.attrs.create('vmat_s', vmat_s) else: # dataset version self.grain_grp.create_dataset('rmat_c', data=rmat_c) self.grain_grp.create_dataset('tvec_c', data=tvec_c) self.grain_grp.create_dataset('inv(V)_s', data=vinv_s) self.grain_grp.create_dataset('vmat_s', data=vmat_s) data_key = 'reflection_data' self.data_grp = self.fid.create_group(data_key) for det_key in self.instr_grp['detectors'].keys(): self.data_grp.create_group(det_key)
def oscillAnglesOfHKLs(hkls, chi, rMat_c, bMat, wavelength, vInv=vInv_ref, beamVec=bVec_ref, etaVec=eta_ref): """ Takes a list of unit reciprocal lattice vectors in crystal frame to the specified detector-relative frame, subject to the conditions: 1) the reciprocal lattice vector must be able to satisfy a bragg condition 2) the associated diffracted beam must intersect the detector plane Required Arguments: hkls -- (3, n) ndarray of n reciprocal lattice vectors in the CRYSTAL FRAME chi -- float representing the inclination angle of the oscillation axis (std coords) rMat_c -- (3, 3) ndarray, the COB taking CRYSTAL FRAME components to SAMPLE FRAME bMat -- (3, 3) ndarray, the COB taking RECIPROCAL LATTICE components to CRYSTAL FRAME wavelength -- float representing the x-ray wavelength in Angstroms Optional Keyword Arguments: beamVec -- (3, 1) ndarray containing the incident beam direction components in the LAB FRAME etaVec -- (3, 1) ndarray containing the reference azimuth direction components in the LAB FRAME vInv -- (6, 1) ndarray containing the indep. components of the inverse left stretch tensor in the SAMPLE FRAME in the Mandel-Voigt notation Outputs: ome0 -- (3, n) ndarray containing the feasible (tTh, eta, ome) triplets for each input hkl (first solution) ome1 -- (3, n) ndarray containing the feasible (tTh, eta, ome) triplets for each input hkl (second solution) Notes: ------------------------------------------------------------------------ The reciprocal lattice vector, G, will satisfy the the Bragg condition when: b.T * G / ||G|| = -sin(theta) where b is the incident beam direction (k_i) and theta is the Bragg angle consistent with G and the specified wavelength. The components of G in the lab frame in this case are obtained using the crystal orientation, Rc, and the single-parameter oscillation matrix, Rs(ome): Rs(ome) * Rc * G / ||G|| The equation above can be rearranged to yeild an expression of the form: a*sin(ome) + b*cos(ome) = c which is solved using the relation: a*sin(x) + b*cos(x) = sqrt(a**2 + b**2) * sin(x + alpha) --> sin(x + alpha) = c / sqrt(a**2 + b**2) where: alpha = arctan2(b, a) The solutions are: / | arcsin(c / sqrt(a**2 + b**2)) - alpha x = < | pi - arcsin(c / sqrt(a**2 + b**2)) - alpha \ There is a double root in the case the reflection is tangent to the Debye-Scherrer cone (c**2 = a**2 + b**2), and no solution if the Laue condition cannot be satisfied (filled with NaNs in the results array here) """ gVec_c = np.dot(bMat, hkls) # reciprocal lattice vectors in CRYSTAL frame vMat_s = mutil.vecMVToSymm(vInv) # stretch tensor in SAMPLE frame gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) # reciprocal lattice vectors in SAMPLE frame gHat_s = unitVector(gVec_s) # unit reciprocal lattice vectors in SAMPLE frame gHat_c = np.dot(rMat_c.T, gHat_s) # unit reciprocal lattice vectors in CRYSTAL frame bHat_l = unitVector(beamVec.reshape(3, 1)) # make sure beam direction is a unit vector eHat_l = unitVector(etaVec.reshape(3, 1)) # make sure eta=0 direction is a unit vector sintht = 0.5 * wavelength * columnNorm(gVec_s) # sin of the Bragg angle assoc. with wavelength cchi = np.cos(chi); schi = np.sin(chi) # sin and cos of the oscillation axis tilt # coefficients for harmonic equation a = gHat_s[2, :]*bHat_l[0] + schi*gHat_s[0, :]*bHat_l[1] - cchi*gHat_s[0, :]*bHat_l[2] b = gHat_s[0, :]*bHat_l[0] - schi*gHat_s[2, :]*bHat_l[1] + cchi*gHat_s[2, :]*bHat_l[2] c = -sintht - cchi*gHat_s[1, :]*bHat_l[1] - schi*gHat_s[1, :]*bHat_l[2] # should all be 1-d: a = a.flatten(); b = b.flatten(); c = c.flatten() # form solution abMag = np.sqrt(a*a + b*b); assert np.all(abMag > 0), "Beam vector specification is infealible!" phaseAng = np.arctan2(b, a) rhs = c / abMag; rhs[abs(rhs) > 1.] = np.nan rhsAng = np.arcsin(rhs) # verified will give NaN for abs(rhs) > 1. + 0.5*epsf # write ome angle output arrays (NaNs persist here) ome0 = rhsAng - phaseAng ome1 = np.pi - rhsAng - phaseAng goodOnes_s = -np.isnan(ome0) # DEBUGGING assert np.all(np.isnan(ome0) == np.isnan(ome1)), "infeasible hkls do not match for ome0, ome1!" # do etas -- ONLY COMPUTE IN CASE CONSISTENT REFERENCE COORDINATES if abs(np.dot(bHat_l.T, eHat_l)) < 1. - sqrt_epsf and np.any(goodOnes_s): eta0 = np.nan * np.ones_like(ome0) eta1 = np.nan * np.ones_like(ome1) # make eta basis COB with beam antiparallel with Z rMat_e = makeEtaFrameRotMat(bHat_l, eHat_l) goodOnes = np.tile(goodOnes_s, (1, 2)).flatten() numGood_s = sum(goodOnes_s) numGood = 2 * numGood_s tmp_eta = np.empty(numGood) tmp_gvec = np.tile(gHat_c, (1, 2))[:, goodOnes] allome = np.hstack([ome0, ome1]) for i in range(numGood): rMat_s = makeOscillRotMat([chi, allome[goodOnes][i]]) gVec_e = np.dot(rMat_e.T, np.dot(rMat_s, np.dot(rMat_c, tmp_gvec[:, i].reshape(3, 1) ) ) ) tmp_eta[i] = np.arctan2(gVec_e[1], gVec_e[0]) pass eta0[goodOnes_s] = tmp_eta[:numGood_s] eta1[goodOnes_s] = tmp_eta[numGood_s:] # make assoc tTh array tTh = 2.*np.arcsin(sintht).flatten() tTh0 = tTh; tTh0[-goodOnes_s] = np.nan retval = (np.vstack([tTh0.flatten(), eta0.flatten(), ome0.flatten()]), np.vstack([tTh0.flatten(), eta1.flatten(), ome1.flatten()]),) else: retval = (ome0.flatten(), ome1.flatten()) pass return retval
def oscillAnglesOfHKLs(hkls, chi, rMat_c, bMat, wavelength, vInv=vInv_ref, beamVec=bVec_ref, etaVec=eta_ref): """ Parameters ---------- hkls : numpy.ndarray (3, n_) array of reciprocal lattice vector components. chi : scalar the inclination angle of the SAMPLE FRAME about the LAB X. rMat_c : numpy.ndarray (3, 3) array, the COB taking CRYSTAL FRAME components to SAMPLE FRAME. bMat : numpy.ndarray (3, 3) array, the COB matrix taking RECIPROCAL FRAME components to the CRYSTAL FRAME. wavelength : scalar the X-ray wavelength in Ångstroms. vInv : numpy.ndarray, optional (6, 1) array representing the components of the inverse stretch tensor in the SAMPLE FRAME. The default is vInv_ref. beamVec : numpy.ndarray, optional (3, 1) array, the vector pointing to the X-ray source in the LAB FRAME. The default is bVec_ref. etaVec : numpy.ndarray, optional (3, 1) array, the vector defining eta=0 in the LAB FRAME. The default is eta_ref. Returns ------- retval : tuple Two (3, n) numpy.ndarrays representing the pair of feasible (tTh, eta, ome) solutions for the n input hkls. Notes ----- The reciprocal lattice vector, G, will satisfy the the Bragg condition when: b.T * G / ||G|| = -sin(theta) where b is the incident beam direction (k_i) and theta is the Bragg angle consistent with G and the specified wavelength. The components of G in the lab frame in this case are obtained using the crystal orientation, Rc, and the single-parameter oscillation matrix, Rs(ome): Rs(ome) * Rc * G / ||G|| The equation above can be rearranged to yeild an expression of the form: a*sin(ome) + b*cos(ome) = c which is solved using the relation: a*sin(x) + b*cos(x) = sqrt(a**2 + b**2) * sin(x + alpha) --> sin(x + alpha) = c / sqrt(a**2 + b**2) where: alpha = arctan2(b, a) The solutions are: / | arcsin(c / sqrt(a**2 + b**2)) - alpha x = < | pi - arcsin(c / sqrt(a**2 + b**2)) - alpha \\ There is a double root in the case the reflection is tangent to the Debye-Scherrer cone (c**2 = a**2 + b**2), and no solution if the Laue condition cannot be satisfied (filled with NaNs in the results array here) """ # reciprocal lattice vectors in CRYSTAL frame gVec_c = np.dot(bMat, hkls) # stretch tensor in SAMPLE frame vMat_s = mutil.vecMVToSymm(vInv) # reciprocal lattice vectors in SAMPLE frame gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) # unit reciprocal lattice vectors in SAMPLE frame gHat_s = unitVector(gVec_s) # unit reciprocal lattice vectors in CRYSTAL frame gHat_c = np.dot(rMat_c.T, gHat_s) # make sure beam direction is a unit vector bHat_l = unitVector(beamVec.reshape(3, 1)) # make sure eta = 0 direction is a unit vector eHat_l = unitVector(etaVec.reshape(3, 1)) # sin of the Bragg angle assoc. with wavelength sintht = 0.5 * wavelength * columnNorm(gVec_s) # sin and cos of the oscillation axis tilt cchi = np.cos(chi) schi = np.sin(chi) # coefficients for harmonic equation a = gHat_s[2, :]*bHat_l[0] \ + schi*gHat_s[0, :]*bHat_l[1] - cchi*gHat_s[0, :]*bHat_l[2] b = gHat_s[0, :]*bHat_l[0] \ - schi*gHat_s[2, :]*bHat_l[1] + cchi*gHat_s[2, :]*bHat_l[2] c = -sintht - cchi * gHat_s[1, :] * bHat_l[1] - schi * gHat_s[ 1, :] * bHat_l[2] # should all be 1-d: a = a.flatten(); b = b.flatten(); c = c.flatten() # form solution abMag = np.sqrt(a * a + b * b) assert np.all(abMag > 0), "Beam vector specification is infealible!" phaseAng = np.arctan2(b, a) rhs = c / abMag rhs[abs(rhs) > 1.] = np.nan rhsAng = np.arcsin(rhs) # will give NaN for abs(rhs) > 1. + 0.5*epsf # write ome angle output arrays (NaNs persist here) ome0 = rhsAng - phaseAng ome1 = np.pi - rhsAng - phaseAng goodOnes_s = -np.isnan(ome0) # DEBUGGING assert np.all(np.isnan(ome0) == np.isnan(ome1)), \ "infeasible hkls do not match for ome0, ome1!" # do etas -- ONLY COMPUTE IN CASE CONSISTENT REFERENCE COORDINATES if abs(np.dot(bHat_l.T, eHat_l)) < 1. - sqrt_epsf and np.any(goodOnes_s): eta0 = np.nan * np.ones_like(ome0) eta1 = np.nan * np.ones_like(ome1) # make eta basis COB with beam antiparallel with Z rMat_e = makeEtaFrameRotMat(bHat_l, eHat_l) goodOnes = np.tile(goodOnes_s, (1, 2)).flatten() numGood_s = sum(goodOnes_s) numGood = 2 * numGood_s tmp_eta = np.empty(numGood) tmp_gvec = np.tile(gHat_c, (1, 2))[:, goodOnes] allome = np.hstack([ome0, ome1]) for i in range(numGood): rMat_s = makeOscillRotMat([chi, allome[goodOnes][i]]) gVec_e = np.dot( rMat_e.T, np.dot(rMat_s, np.dot(rMat_c, tmp_gvec[:, i].reshape(3, 1)))) tmp_eta[i] = np.arctan2(gVec_e[1], gVec_e[0]) pass eta0[goodOnes_s] = tmp_eta[:numGood_s] eta1[goodOnes_s] = tmp_eta[numGood_s:] # make assoc tTh array tTh = 2. * np.arcsin(sintht).flatten() tTh0 = tTh tTh0[-goodOnes_s] = np.nan retval = ( np.vstack([tTh0.flatten(), eta0.flatten(), ome0.flatten()]), np.vstack([tTh0.flatten(), eta1.flatten(), ome1.flatten()]), ) else: retval = (ome0.flatten(), ome1.flatten()) pass return retval
def get_e_mat(self, grain_params): """ strain tensor calculation """ return logm(np.linalg.inv(vecMVToSymm(grain_params[6:])))
def sxcal_obj_func(plist_fit, plist_full, param_flags, dfuncs, dparam_flags, ndparams, instr, xyo_det, hkls_idx, bmat, vinv_s, ome_period, bvec, evec, sim_only=False, return_value_flag=None): """ """ # stack flags and force bool repr refine_flags = np.array(np.hstack([param_flags, dparam_flags]), dtype=bool) # fill out full parameter list # !!! no scaling for now plist_full[refine_flags] = plist_fit # instrument quantities wavelength = plist_full[0] chi = plist_full[1] tvec_s = plist_full[2:5] # calibration crystal quantities rmat_c = xfcapi.makeRotMatOfExpMap(plist_full[5:8]) tvec_c = plist_full[8:11] # right now just stuck on the end and assumed # to all be the same length... FIX THIS dparams_all = plist_full[-len(dparam_flags):] xy_unwarped = {} meas_omes = {} calc_omes = {} calc_xy = {} ii = 11 # offset to start of panels... jj = 0 npts_tot = 0 for det_key, panel in instr.detectors.iteritems(): xy_unwarped[det_key] = xyo_det[det_key][:, :2] npts_tot += len(xyo_det[det_key]) dfunc = dfuncs[det_key] len_these_dps = ndparams[det_key] if dfunc is not None: # do unwarping dparams = dparams_all[jj:jj + len_these_dps] jj += len_these_dps xy_unwarped[det_key] = dfunc(xy_unwarped[det_key], dparams) pass meas_omes[det_key] = xyo_det[det_key][:, 2] # get these panel params for convenience gparams = plist_full[ii:ii + 6] rmat_d = xfcapi.makeDetectorRotMat(gparams[:3]) tvec_d = gparams[3:].reshape(3, 1) # transform G-vectors: # 1) convert inv. stretch tensor from MV notation in to 3x3 # 2) take reciprocal lattice vectors from CRYSTAL to SAMPLE frame # 3) apply stretch tensor # 4) normalize reciprocal lattice vectors in SAMPLE frame # 5) transform unit reciprocal lattice vetors back to CRYSAL frame gvec_c = np.dot(bmat, hkls_idx[det_key].T) vmat_s = mutil.vecMVToSymm(vinv_s) ghat_s = mutil.unitVector(np.dot(vmat_s, np.dot(rmat_c, gvec_c))) ghat_c = np.dot(rmat_c.T, ghat_s) match_omes, calc_omes_tmp = fitting.matchOmegas(xyo_det[det_key], hkls_idx[det_key].T, chi, rmat_c, bmat, wavelength, vInv=vinv_s, beamVec=bvec, etaVec=evec, omePeriod=ome_period) rmat_s_arr = xfcapi.makeOscillRotMatArray( chi, np.ascontiguousarray(calc_omes_tmp)) calc_xy_tmp = xfcapi.gvecToDetectorXYArray(ghat_c.T, rmat_d, rmat_s_arr, rmat_c, tvec_d, tvec_s, tvec_c) if np.any(np.isnan(calc_xy_tmp)): print("infeasible parameters: " + "may want to scale back finite difference step size") calc_omes[det_key] = calc_omes_tmp calc_xy[det_key] = calc_xy_tmp ii += 6 pass # return values if sim_only: retval = {} for det_key in calc_xy.keys(): # ??? calc_xy is always 2-d retval[det_key] = np.vstack( [calc_xy[det_key].T, calc_omes[det_key]]).T else: meas_xy_all = [] calc_xy_all = [] meas_omes_all = [] calc_omes_all = [] for det_key in xy_unwarped.keys(): meas_xy_all.append(xy_unwarped[det_key]) calc_xy_all.append(calc_xy[det_key]) meas_omes_all.append(meas_omes[det_key]) calc_omes_all.append(calc_omes[det_key]) pass meas_xy_all = np.vstack(meas_xy_all) calc_xy_all = np.vstack(calc_xy_all) meas_omes_all = np.hstack(meas_omes_all) calc_omes_all = np.hstack(calc_omes_all) diff_vecs_xy = calc_xy_all - meas_xy_all diff_ome = xfcapi.angularDifference(calc_omes_all, meas_omes_all) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts_tot, 1)]).flatten() if return_value_flag == 1: retval = sum(abs(retval)) elif return_value_flag == 2: denom = npts_tot - len(plist_fit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. nu_fac = 1 / (npts_tot - len(plist_fit) - 1.) retval = nu_fac * sum(retval**2) return retval
def compare_grain_fits(fit_grain_params, ref_grain_params, mtol=1.e-4, ctol=1.e-3, vtol=1.e-4): """ Executes comparison between reference and fit grain parameters for ff-HEDM for the same initial parameters. Parameters ---------- fit_grain_params : array_like, (n, 12) The fit grain parameters to be tested. ref_grain_params : array_like, (n, 12) The reference grain parameters (see Notes below). Returns ------- bool True is successful comparison Notes ----- The fitgrains action currently returns grain_id, completeness, chisq, grain_params. We will have to assume that the grain_ids are in the *same order* as the reference, which can be enforces by running the comparison using the reference orientation list. """ fit_grain_params = np.atleast_2d(fit_grain_params) ref_grain_params = np.atleast_2d(ref_grain_params) cresult = False ii = 0 for fg, rg in zip(fit_grain_params, ref_grain_params): # test_orientation quats = rot.quatOfExpMap(np.vstack([fg[:3], rg[:3]]).T) ang, mis = rot.misorientation(quats[:, 0].reshape(4, 1), quats[:, 1].reshape(4, 1)) if ang <= mtol: cresult = True else: print("orientations for grain %d do not agree." % ii) return cresult # test position if np.linalg.norm(fg[3:6] - rg[3:6]) > ctol: print("centroidal coordinates for grain %d do not agree." % ii) return False # test strain vmat_fit = mutil.symmToVecMV(np.linalg.inv(mutil.vecMVToSymm(fg[6:])), scale=False) vmat_ref = mutil.symmToVecMV(np.linalg.inv(mutil.vecMVToSymm(rg[6:])), scale=False) if np.linalg.norm(vmat_fit - vmat_ref, ord=1) > vtol: print("stretch components for grain %d do not agree." % ii) return False # index grain id ii += 1 return cresult
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 objFuncFitGrain(gFit, gFull, gFlag, instrument, reflections_dict, bMat, wavelength, omePeriod, simOnly=False, return_value_flag=return_value_flag): """ gFull[0] = expMap_c[0] gFull[1] = expMap_c[1] gFull[2] = expMap_c[2] gFull[3] = tVec_c[0] gFull[4] = tVec_c[1] gFull[5] = tVec_c[2] gFull[6] = vInv_MV[0] gFull[7] = vInv_MV[1] gFull[8] = vInv_MV[2] gFull[9] = vInv_MV[3] gFull[10] = vInv_MV[4] gFull[11] = vInv_MV[5] OLD CALL objFuncFitGrain(gFit, gFull, gFlag, detectorParams, xyo_det, hkls_idx, bMat, wavelength, bVec, eVec, dFunc, dParams, omePeriod, simOnly=False, return_value_flag=return_value_flag) """ bVec = instrument.beam_vector eVec = instrument.eta_vector # fill out parameters gFull[gFlag] = gFit # map parameters to functional arrays rMat_c = xfcapi.makeRotMatOfExpMap(gFull[:3]) tVec_c = gFull[3:6].reshape(3, 1) vInv_s = gFull[6:] vMat_s = mutil.vecMVToSymm(vInv_s) # NOTE: Inverse of V from F = V * R # loop over instrument panels # CAVEAT: keeping track of key ordering in the "detectors" attribute of # instrument here because I am not sure if instatiating them using # dict.fromkeys() preserves the same order if using iteration... # <JVB 2017-10-31> calc_omes_dict = dict.fromkeys(instrument.detectors, []) calc_xy_dict = dict.fromkeys(instrument.detectors) meas_xyo_all = [] det_keys_ordered = [] for det_key, panel in instrument.detectors.iteritems(): det_keys_ordered.append(det_key) rMat_d, tVec_d, chi, tVec_s = extract_detector_transformation( instrument.detector_parameters[det_key]) results = reflections_dict[det_key] if len(results) == 0: continue """ extract data from results list fields: refl_id, gvec_id, hkl, sum_int, max_int, pred_ang, meas_ang, meas_xy or array from spots tables: 0:5 ID PID H K L 5:7 sum(int) max(int) 7:10 pred tth pred eta pred ome 10:13 meas tth meas eta meas ome 13:15 pred X pred Y 15:17 meas X meas Y """ if isinstance(results, list): # WARNING: hkls and derived vectors below must be columnwise; # strictly necessary??? change affected APIs instead? # <JVB 2017-03-26> hkls = np.atleast_2d( np.vstack([x[2] for x in results]) ).T meas_xyo = np.atleast_2d( np.vstack([np.r_[x[7], x[6][-1]] for x in results]) ) elif isinstance(results, np.ndarray): hkls = np.atleast_2d(results[:, 2:5]).T meas_xyo = np.atleast_2d(results[:, [15, 16, 12]]) # FIXME: distortion handling must change to class-based if panel.distortion is not None: meas_omes = meas_xyo[:, 2] xy_unwarped = panel.distortion[0]( meas_xyo[:, :2], panel.distortion[1]) meas_xyo = np.vstack([xy_unwarped.T, meas_omes]).T pass # append to meas_omes meas_xyo_all.append(meas_xyo) # G-vectors: # 1. calculate full g-vector components in CRYSTAL frame from B # 2. rotate into SAMPLE frame and apply stretch # 3. rotate back into CRYSTAL frame and normalize to unit magnitude # IDEA: make a function for this sequence of operations with option for # choosing ouput frame (i.e. CRYSTAL vs SAMPLE vs LAB) gVec_c = np.dot(bMat, hkls) gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) gHat_c = mutil.unitVector(np.dot(rMat_c.T, gVec_s)) # !!!: check that this operates on UNWARPED xy match_omes, calc_omes = matchOmegas( meas_xyo, hkls, chi, rMat_c, bMat, wavelength, vInv=vInv_s, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) # append to omes dict calc_omes_dict[det_key] = calc_omes # TODO: try Numba implementations rMat_s = xfcapi.makeOscillRotMatArray(chi, calc_omes) calc_xy = xfcapi.gvecToDetectorXYArray(gHat_c.T, rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec) # append to xy dict calc_xy_dict[det_key] = calc_xy pass # stack results to concatenated arrays calc_omes_all = np.hstack([calc_omes_dict[k] for k in det_keys_ordered]) tmp = [] for k in det_keys_ordered: if calc_xy_dict[k] is not None: tmp.append(calc_xy_dict[k]) calc_xy_all = np.vstack(tmp) meas_xyo_all = np.vstack(meas_xyo_all) npts = len(meas_xyo_all) if np.any(np.isnan(calc_xy)): raise RuntimeError( "infeasible pFull: may want to scale" + "back finite difference step size") # return values if simOnly: # return simulated values if return_value_flag in [None, 1]: retval = np.hstack([calc_xy_all, calc_omes_all.reshape(npts, 1)]) else: rd = dict.fromkeys(det_keys_ordered) for det_key in det_keys_ordered: rd[det_key] = {'calc_xy': calc_xy_dict[det_key], 'calc_omes': calc_omes_dict[det_key]} retval = rd else: # return residual vector # IDEA: try angles instead of xys? diff_vecs_xy = calc_xy_all - meas_xyo_all[:, :2] diff_ome = xf.angularDifference(calc_omes_all, meas_xyo_all[:, 2]) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1) ]).flatten() if return_value_flag == 1: # return scalar sum of squared residuals retval = sum(abs(retval)) elif return_value_flag == 2: # return DOF-normalized chisq # TODO: check this calculation denom = 3*npts - len(gFit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. retval = nu_fac * sum(retval**2) return retval
def objFuncSX(pFit, pFull, pFlag, dFunc, dFlag, xyo_det, hkls_idx, bMat, vInv, bVec, eVec, omePeriod, simOnly=False, return_value_flag=return_value_flag): """ """ npts = len(xyo_det) refineFlag = np.array(np.hstack([pFlag, dFlag]), dtype=bool) print refineFlag # pFull[refineFlag] = pFit/scl[refineFlag] pFull[refineFlag] = pFit if dFunc is not None: dParams = pFull[-len(dFlag):] xys = dFunc(xyo_det[:, :2], dParams) else: xys = xyo_det[:, :2] # detector quantities wavelength = pFull[0] rMat_d = xf.makeDetectorRotMat(pFull[1:4]) tVec_d = pFull[4:7].reshape(3, 1) # sample quantities chi = pFull[7] tVec_s = pFull[8:11].reshape(3, 1) # crystal quantities rMat_c = xf.makeRotMatOfExpMap(pFull[11:14]) tVec_c = pFull[14:17].reshape(3, 1) # stretch tensor comp matrix from MV notation in SAMPLE frame vMat_s = mutil.vecMVToSymm(vInv) # g-vectors: # 1. calculate full g-vector components in CRYSTAL frame from B # 2. rotate into SAMPLE frame and apply stretch # 3. rotate back into CRYSTAL frame and normalize to unit magnitude # IDEA: make a function for this sequence of operations with option for # choosing ouput frame (i.e. CRYSTAL vs SAMPLE vs LAB) gVec_c = np.dot(bMat, hkls_idx) gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) gHat_c = mutil.unitVector(np.dot(rMat_c.T, gVec_s)) match_omes, calc_omes = matchOmegas( xyo_det, hkls_idx, chi, rMat_c, bMat, wavelength, vInv=vInv, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) calc_xy = np.zeros((npts, 2)) for i in range(npts): rMat_s = xfcapi.makeOscillRotMat([chi, calc_omes[i]]) calc_xy[i, :] = xfcapi.gvecToDetectorXY(gHat_c[:, i], rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec).flatten() pass if np.any(np.isnan(calc_xy)): raise RuntimeError( "infeasible pFull: may want to scale" + "back finite difference step size") # return values if simOnly: # return simulated values retval = np.hstack([calc_xy, calc_omes.reshape(npts, 1)]) else: # return residual vector # IDEA: try angles instead of xys? diff_vecs_xy = calc_xy - xys[:, :2] diff_ome = xf.angularDifference(calc_omes, xyo_det[:, 2]) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1) ]).flatten() if return_value_flag == 1: # return scalar sum of squared residuals retval = sum(abs(retval)) elif return_value_flag == 2: # return DOF-normalized chisq # TODO: check this calculation denom = npts - len(pFit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. nu_fac = 1 / (npts - len(pFit) - 1.) retval = nu_fac * sum(retval**2) return retval
def objFuncFitGrain(gFit, gFull, gFlag, instrument, reflections_dict, bMat, wavelength, omePeriod, simOnly=False, return_value_flag=return_value_flag): """ Calculate residual between measured and simulated ff-HEDM G-vectors. gFull[0] = expMap_c[0] gFull[1] = expMap_c[1] gFull[2] = expMap_c[2] gFull[3] = tVec_c[0] gFull[4] = tVec_c[1] gFull[5] = tVec_c[2] gFull[6] = vInv_MV[0] gFull[7] = vInv_MV[1] gFull[8] = vInv_MV[2] gFull[9] = vInv_MV[3] gFull[10] = vInv_MV[4] gFull[11] = vInv_MV[5] OLD CALL objFuncFitGrain(gFit, gFull, gFlag, detectorParams, xyo_det, hkls_idx, bMat, wavelength, bVec, eVec, dFunc, dParams, omePeriod, simOnly=False, return_value_flag=return_value_flag) Parameters ---------- gFit : TYPE DESCRIPTION. gFull : TYPE DESCRIPTION. gFlag : TYPE DESCRIPTION. instrument : TYPE DESCRIPTION. reflections_dict : TYPE DESCRIPTION. bMat : TYPE DESCRIPTION. wavelength : TYPE DESCRIPTION. omePeriod : TYPE DESCRIPTION. simOnly : TYPE, optional DESCRIPTION. The default is False. return_value_flag : TYPE, optional DESCRIPTION. The default is return_value_flag. Raises ------ RuntimeError DESCRIPTION. Returns ------- retval : TYPE DESCRIPTION. """ bVec = instrument.beam_vector eVec = instrument.eta_vector # fill out parameters gFull[gFlag] = gFit # map parameters to functional arrays rMat_c = xfcapi.makeRotMatOfExpMap(gFull[:3]) tVec_c = gFull[3:6].reshape(3, 1) vInv_s = gFull[6:] vMat_s = mutil.vecMVToSymm(vInv_s) # NOTE: Inverse of V from F = V * R # loop over instrument panels # CAVEAT: keeping track of key ordering in the "detectors" attribute of # instrument here because I am not sure if instatiating them using # dict.fromkeys() preserves the same order if using iteration... # <JVB 2017-10-31> calc_omes_dict = dict.fromkeys(instrument.detectors, []) calc_xy_dict = dict.fromkeys(instrument.detectors) meas_xyo_all = [] det_keys_ordered = [] for det_key, panel in instrument.detectors.items(): det_keys_ordered.append(det_key) rMat_d, tVec_d, chi, tVec_s = extract_detector_transformation( instrument.detector_parameters[det_key]) results = reflections_dict[det_key] if len(results) == 0: continue """ extract data from results list fields: refl_id, gvec_id, hkl, sum_int, max_int, pred_ang, meas_ang, meas_xy or array from spots tables: 0:5 ID PID H K L 5:7 sum(int) max(int) 7:10 pred tth pred eta pred ome 10:13 meas tth meas eta meas ome 13:15 pred X pred Y 15:17 meas X meas Y """ if isinstance(results, list): # WARNING: hkls and derived vectors below must be columnwise; # strictly necessary??? change affected APIs instead? # <JVB 2017-03-26> hkls = np.atleast_2d(np.vstack([x[2] for x in results])).T meas_xyo = np.atleast_2d( np.vstack([np.r_[x[7], x[6][-1]] for x in results])) elif isinstance(results, np.ndarray): hkls = np.atleast_2d(results[:, 2:5]).T meas_xyo = np.atleast_2d(results[:, [15, 16, 12]]) # distortion handling if panel.distortion is not None: meas_omes = meas_xyo[:, 2] xy_unwarped = panel.distortion.apply(meas_xyo[:, :2]) meas_xyo = np.vstack([xy_unwarped.T, meas_omes]).T pass # append to meas_omes meas_xyo_all.append(meas_xyo) # G-vectors: # 1. calculate full g-vector components in CRYSTAL frame from B # 2. rotate into SAMPLE frame and apply stretch # 3. rotate back into CRYSTAL frame and normalize to unit magnitude # IDEA: make a function for this sequence of operations with option for # choosing ouput frame (i.e. CRYSTAL vs SAMPLE vs LAB) gVec_c = np.dot(bMat, hkls) gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) gHat_c = mutil.unitVector(np.dot(rMat_c.T, gVec_s)) # !!!: check that this operates on UNWARPED xy match_omes, calc_omes = matchOmegas(meas_xyo, hkls, chi, rMat_c, bMat, wavelength, vInv=vInv_s, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) # append to omes dict calc_omes_dict[det_key] = calc_omes # TODO: try Numba implementations rMat_s = xfcapi.makeOscillRotMatArray(chi, calc_omes) calc_xy = xfcapi.gvecToDetectorXYArray(gHat_c.T, rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec) # append to xy dict calc_xy_dict[det_key] = calc_xy pass # stack results to concatenated arrays calc_omes_all = np.hstack([calc_omes_dict[k] for k in det_keys_ordered]) tmp = [] for k in det_keys_ordered: if calc_xy_dict[k] is not None: tmp.append(calc_xy_dict[k]) calc_xy_all = np.vstack(tmp) meas_xyo_all = np.vstack(meas_xyo_all) npts = len(meas_xyo_all) if np.any(np.isnan(calc_xy)): raise RuntimeError("infeasible pFull: may want to scale" + "back finite difference step size") # return values if simOnly: # return simulated values if return_value_flag in [None, 1]: retval = np.hstack([calc_xy_all, calc_omes_all.reshape(npts, 1)]) else: rd = dict.fromkeys(det_keys_ordered) for det_key in det_keys_ordered: rd[det_key] = { 'calc_xy': calc_xy_dict[det_key], 'calc_omes': calc_omes_dict[det_key] } retval = rd else: # return residual vector # IDEA: try angles instead of xys? diff_vecs_xy = calc_xy_all - meas_xyo_all[:, :2] diff_ome = xfcapi.angularDifference(calc_omes_all, meas_xyo_all[:, 2]) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1)]).flatten() if return_value_flag == 1: # return scalar sum of squared residuals retval = sum(abs(retval)) elif return_value_flag == 2: # return DOF-normalized chisq # TODO: check this calculation denom = 3 * npts - len(gFit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. retval = nu_fac * sum(retval**2) return retval
def get_e_mat(self, grain_params): # TODO: document what is this? return logm(np.linalg.inv(vecMVToSymm(grain_params[6:])))
def simulate_laue_pattern(self, crystal_data, minEnergy=5., maxEnergy=35., rmat_s=None, tvec_s=None, grain_params=None, beam_vec=None): """ """ if isinstance(crystal_data, PlaneData): plane_data = crystal_data # grab the expanded list of hkls from plane_data hkls = np.hstack(plane_data.getSymHKLs()) # and the unit plane normals (G-vectors) in CRYSTAL FRAME gvec_c = np.dot(plane_data.latVecOps['B'], hkls) elif len(crystal_data) == 2: # !!! should clean this up hkls = np.array(crystal_data[0]) bmat = crystal_data[1] gvec_c = np.dot(bmat, hkls) else: raise(RuntimeError, 'argument list not understood') nhkls_tot = hkls.shape[1] # parse energy ranges # TODO: allow for spectrum parsing 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(ct.keVToAngstrom(maxEnergy[i])) lmax.append(ct.keVToAngstrom(minEnergy[i])) else: lmin = ct.keVToAngstrom(maxEnergy) lmax = ct.keVToAngstrom(minEnergy) # parse grain parameters kwarg if grain_params is None: grain_params = np.atleast_2d( np.hstack([np.zeros(6), ct.identity_6x1]) ) n_grains = len(grain_params) # sample rotation if rmat_s is None: rmat_s = ct.identity_3x3 # dummy translation vector... make input if tvec_s is None: tvec_s = ct.zeros_3 # beam vector if beam_vec is None: beam_vec = ct.beam_vec # ========================================================================= # LOOP OVER GRAINS # ========================================================================= # 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)) for iG, gp in enumerate(grain_params): rmat_c = 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 gvec_s_str = np.dot(vInv_s, np.dot(rmat_c, gvec_c)) ghat_c_str = mutil.unitVector(np.dot(rmat_c.T, gvec_s_str)) # project dpts = gvecToDetectorXY(ghat_c_str.T, self.rmat, rmat_s, rmat_c, self.tvec, tvec_s, tvec_c, beamVec=beam_vec) # check intersections with detector plane canIntersect = ~np.isnan(dpts[:, 0]) npts_in = sum(canIntersect) if np.any(canIntersect): dpts = dpts[canIntersect, :].reshape(npts_in, 2) dhkl = hkls[:, canIntersect].reshape(3, npts_in) # back to angles tth_eta, gvec_l = detectorXYToGvec( dpts, self.rmat, rmat_s, self.tvec, tvec_s, tvec_c, beamVec=beam_vec) tth_eta = np.vstack(tth_eta).T # warp measured points if self.distortion is not None: if len(self.distortion) == 2: dpts = self.distortion[0]( dpts, self.distortion[1], invert=True) else: raise(RuntimeError, "something is wrong with the distortion") # plane spacings and energies dsp = 1. / rowNorm(gvec_s_str[:, canIntersect].T) wlen = 2*dsp*np.sin(0.5*tth_eta[:, 0]) # clip to detector panel _, on_panel = self.clip_to_panel(dpts, buffer_edges=True) if multipleEnergyRanges: validEnergy = np.zeros(len(wlen), dtype=bool) for i in range(len(lmin)): in_energy_range = np.logical_and( wlen >= lmin[i], wlen <= lmax[i]) validEnergy = validEnergy | in_energy_range pass else: validEnergy = np.logical_and(wlen >= lmin, wlen <= lmax) pass # index for valid reflections keepers = np.where(np.logical_and(on_panel, validEnergy))[0] # assign output arrays xy_det[iG][keepers, :] = dpts[keepers, :] hkls_in[iG][:, keepers] = dhkl[:, keepers] angles[iG][keepers, :] = tth_eta[keepers, :] dspacing[iG, keepers] = dsp[keepers] energy[iG, keepers] = ct.keVToAngstrom(wlen[keepers]) pass # close conditional on valids pass # close loop on grains return xy_det, hkls_in, angles, dspacing, energy
def objFuncFitGrain(gFit, gFull, gFlag, detectorParams, xyo_det, hkls_idx, bMat, wavelength, bVec, eVec, dFunc, dParams, omePeriod, simOnly=False, returnScalarValue=returnScalarValue): """ gFull[0] = expMap_c[0] gFull[1] = expMap_c[1] gFull[2] = expMap_c[2] gFull[3] = tVec_c[0] gFull[4] = tVec_c[1] gFull[5] = tVec_c[2] gFull[6] = vInv_MV[0] gFull[7] = vInv_MV[1] gFull[8] = vInv_MV[2] gFull[9] = vInv_MV[3] gFull[10] = vInv_MV[4] gFull[11] = vInv_MV[5] detectorParams[0] = tiltAngles[0] detectorParams[1] = tiltAngles[1] detectorParams[2] = tiltAngles[2] detectorParams[3] = tVec_d[0] detectorParams[4] = tVec_d[1] detectorParams[5] = tVec_d[2] detectorParams[6] = chi detectorParams[7] = tVec_s[0] detectorParams[8] = tVec_s[1] detectorParams[9] = tVec_s[2] """ npts = len(xyo_det) gFull[gFlag] = gFit xy_unwarped = dFunc(xyo_det[:, :2], dParams) rMat_d = xfcapi.makeDetectorRotMat(detectorParams[:3]) tVec_d = detectorParams[3:6].reshape(3, 1) chi = detectorParams[6] tVec_s = detectorParams[7:10].reshape(3, 1) rMat_c = xfcapi.makeRotMatOfExpMap(gFull[:3]) tVec_c = gFull[3:6].reshape(3, 1) vInv_s = gFull[6:] vMat_s = mutil.vecMVToSymm(vInv_s) # NOTE: Inverse of V from F = V * R gVec_c = np.dot(bMat, hkls_idx) # gVecs with magnitudes in CRYSTAL frame gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) # stretched gVecs in SAMPLE frame gHat_c = mutil.unitVector( np.dot(rMat_c.T, gVec_s)) # unit reciprocal lattice vectors in CRYSTAL frame match_omes, calc_omes = matchOmegas(xyo_det, hkls_idx, chi, rMat_c, bMat, wavelength, vInv=vInv_s, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) calc_xy = np.zeros((npts, 2)) for i in range(npts): rMat_s = xfcapi.makeOscillRotMat([chi, calc_omes[i]]) calc_xy[i, :] = xfcapi.gvecToDetectorXY(gHat_c[:, i], rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec).flatten() pass if np.any(np.isnan(calc_xy)): print "infeasible pFull" # return values if simOnly: retval = np.hstack([calc_xy, calc_omes.reshape(npts, 1)]) else: diff_vecs_xy = calc_xy - xy_unwarped[:, :2] diff_ome = xf.angularDifference( calc_omes, xyo_det[:, 2] ) retval = mutil.rowNorm( np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1) ]) ).flatten() if returnScalarValue: retval = sum( retval ) return retval
fid = open(filename %grainID, 'w') sd = xrdutil.pullSpots(pd, detector_params, g_refined, reader, distortion=(dFunc, dParams), eta_range=etaRange, ome_period=ome_period, tth_tol=tth_tol_r, eta_tol=eta_tol_r, ome_tol=ome_tol_r, panel_buff=[10, 10], npdiv=2, threshold=threshold, use_closest=True, doClipping=False, filename=fid) fid.close() pass else: g_refined = grain_params break pass eMat = logm(np.linalg.inv(mutil.vecMVToSymm(g_refined[6:]))) resd_f2 = fitting.objFuncFitGrain(g_refined[gFlag], g_refined, gFlag, detector_params, xyo_det, hkls, bMat, wlen, bVec_ref, eta_ref, dFunc, dParams, ome_period, simOnly=False) print >> grains_file, \ "%d\t%1.7e\t%1.7e\t" % (grainID, sum(idx)/float(len(idx)), sum(resd_f2**2)) + \ "%1.7e\t%1.7e\t%1.7e\t" % tuple(g_refined[:3]) + \ "%1.7e\t%1.7e\t%1.7e\t" % tuple(g_refined[3:6]) + \ "%1.7e\t%1.7e\t%1.7e\t%1.7e\t%1.7e\t%1.7e\t" % tuple(g_refined[6:]) + \ "%1.7e\t%1.7e\t%1.7e\t%1.7e\t%1.7e\t%1.7e" % (eMat[0, 0], eMat[1, 1], eMat[2, 2], eMat[1, 2], eMat[0, 2], eMat[0, 1]) elapsed = (time.clock() - start)
def inverse_stretch(self, v): m = matrixutil.vecMVToSymm(v, scale=True) self.stretch_matrix = np.linalg.inv(m).flatten()
def objFuncFitGrain(gFit, gFull, gFlag, detectorParams, xyo_det, hkls_idx, bMat, wavelength, bVec, eVec, dFunc, dParams, omePeriod, simOnly=False, return_value_flag=return_value_flag): """ gFull[0] = expMap_c[0] gFull[1] = expMap_c[1] gFull[2] = expMap_c[2] gFull[3] = tVec_c[0] gFull[4] = tVec_c[1] gFull[5] = tVec_c[2] gFull[6] = vInv_MV[0] gFull[7] = vInv_MV[1] gFull[8] = vInv_MV[2] gFull[9] = vInv_MV[3] gFull[10] = vInv_MV[4] gFull[11] = vInv_MV[5] detectorParams[0] = tiltAngles[0] detectorParams[1] = tiltAngles[1] detectorParams[2] = tiltAngles[2] detectorParams[3] = tVec_d[0] detectorParams[4] = tVec_d[1] detectorParams[5] = tVec_d[2] detectorParams[6] = chi detectorParams[7] = tVec_s[0] detectorParams[8] = tVec_s[1] detectorParams[9] = tVec_s[2] """ npts = len(xyo_det) gFull[gFlag] = gFit xy_unwarped = dFunc(xyo_det[:, :2], dParams) rMat_d = xfcapi.makeDetectorRotMat(detectorParams[:3]) tVec_d = detectorParams[3:6].reshape(3, 1) chi = detectorParams[6] tVec_s = detectorParams[7:10].reshape(3, 1) rMat_c = xfcapi.makeRotMatOfExpMap(gFull[:3]) tVec_c = gFull[3:6].reshape(3, 1) vInv_s = gFull[6:] vMat_s = mutil.vecMVToSymm(vInv_s) # NOTE: Inverse of V from F = V * R gVec_c = np.dot(bMat, hkls_idx) # gVecs with magnitudes in CRYSTAL frame gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) # stretched gVecs in SAMPLE frame gHat_c = mutil.unitVector(np.dot( rMat_c.T, gVec_s)) # unit reciprocal lattice vectors in CRYSTAL frame match_omes, calc_omes = matchOmegas(xyo_det, hkls_idx, chi, rMat_c, bMat, wavelength, vInv=vInv_s, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) rMat_s = xfcapi.makeOscillRotMatArray(chi, calc_omes) calc_xy = xfcapi.gvecToDetectorXYArray(gHat_c.T, rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec) if np.any(np.isnan(calc_xy)): print "infeasible pFull" # return values if simOnly: retval = np.hstack([calc_xy, calc_omes.reshape(npts, 1)]) else: diff_vecs_xy = calc_xy - xy_unwarped[:, :2] diff_ome = xf.angularDifference(calc_omes, xyo_det[:, 2]) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1)]).flatten() if return_value_flag == 1: retval = sum(abs(retval)) elif return_value_flag == 2: denom = npts - len(gFit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. retval = nu_fac * sum(retval**2 / abs( np.hstack([calc_xy, calc_omes.reshape(npts, 1)]).flatten())) return retval
def oscillAnglesOfHKLs(hkls, chi, rMat_c, bMat, wavelength, vInv=vInv_ref, beamVec=bVec_ref, etaVec=eta_ref): """ Takes a list of unit reciprocal lattice vectors in crystal frame to the specified detector-relative frame, subject to the conditions: 1) the reciprocal lattice vector must be able to satisfy a bragg condition 2) the associated diffracted beam must intersect the detector plane Required Arguments: hkls -- (3, n) ndarray of n reciprocal lattice vectors in the CRYSTAL FRAME chi -- float representing the inclination angle of the oscillation axis (std coords) rMat_c -- (3, 3) ndarray, the COB taking CRYSTAL FRAME components to SAMPLE FRAME bMat -- (3, 3) ndarray, the COB taking RECIPROCAL LATTICE components to CRYSTAL FRAME wavelength -- float representing the x-ray wavelength in Angstroms Optional Keyword Arguments: beamVec -- (3, 1) ndarray containing the incident beam direction components in the LAB FRAME etaVec -- (3, 1) ndarray containing the reference azimuth direction components in the LAB FRAME vInv -- (6, 1) ndarray containing the indep. components of the inverse left stretch tensor in the SAMPLE FRAME in the Mandel-Voigt notation Outputs: ome0 -- (3, n) ndarray containing the feasible (tTh, eta, ome) triplets for each input hkl (first solution) ome1 -- (3, n) ndarray containing the feasible (tTh, eta, ome) triplets for each input hkl (second solution) Notes: ------------------------------------------------------------------------ The reciprocal lattice vector, G, will satisfy the the Bragg condition when: b.T * G / ||G|| = -sin(theta) where b is the incident beam direction (k_i) and theta is the Bragg angle consistent with G and the specified wavelength. The components of G in the lab frame in this case are obtained using the crystal orientation, Rc, and the single-parameter oscillation matrix, Rs(ome): Rs(ome) * Rc * G / ||G|| The equation above can be rearranged to yeild an expression of the form: a*sin(ome) + b*cos(ome) = c which is solved using the relation: a*sin(x) + b*cos(x) = sqrt(a**2 + b**2) * sin(x + alpha) --> sin(x + alpha) = c / sqrt(a**2 + b**2) where: alpha = arctan2(b, a) The solutions are: / | arcsin(c / sqrt(a**2 + b**2)) - alpha x = < | pi - arcsin(c / sqrt(a**2 + b**2)) - alpha \ There is a double root in the case the reflection is tangent to the Debye-Scherrer cone (c**2 = a**2 + b**2), and no solution if the Laue condition cannot be satisfied (filled with NaNs in the results array here) """ gVec_c = np.dot(bMat, hkls) # reciprocal lattice vectors in CRYSTAL frame vMat_s = mutil.vecMVToSymm(vInv) # stretch tensor in SAMPLE frame gVec_s = np.dot(vMat_s, np.dot( rMat_c, gVec_c)) # reciprocal lattice vectors in SAMPLE frame gHat_s = unitVector( gVec_s) # unit reciprocal lattice vectors in SAMPLE frame gHat_c = np.dot(rMat_c.T, gHat_s) # unit reciprocal lattice vectors in CRYSTAL frame bHat_l = unitVector(beamVec.reshape( 3, 1)) # make sure beam direction is a unit vector eHat_l = unitVector(etaVec.reshape( 3, 1)) # make sure eta=0 direction is a unit vector sintht = 0.5 * wavelength * columnNorm( gVec_s) # sin of the Bragg angle assoc. with wavelength cchi = np.cos(chi) schi = np.sin(chi) # sin and cos of the oscillation axis tilt # coefficients for harmonic equation a = gHat_s[2, :] * bHat_l[0] + schi * gHat_s[ 0, :] * bHat_l[1] - cchi * gHat_s[0, :] * bHat_l[2] b = gHat_s[0, :] * bHat_l[0] - schi * gHat_s[ 2, :] * bHat_l[1] + cchi * gHat_s[2, :] * bHat_l[2] c = -sintht - cchi * gHat_s[1, :] * bHat_l[1] - schi * gHat_s[ 1, :] * bHat_l[2] # should all be 1-d: a = a.flatten(); b = b.flatten(); c = c.flatten() # form solution abMag = np.sqrt(a * a + b * b) assert np.all(abMag > 0), "Beam vector specification is infealible!" phaseAng = np.arctan2(b, a) rhs = c / abMag rhs[abs(rhs) > 1.] = np.nan rhsAng = np.arcsin( rhs) # verified will give NaN for abs(rhs) > 1. + 0.5*epsf # write ome angle output arrays (NaNs persist here) ome0 = rhsAng - phaseAng ome1 = np.pi - rhsAng - phaseAng goodOnes_s = -np.isnan(ome0) # DEBUGGING assert np.all(np.isnan(ome0) == np.isnan( ome1)), "infeasible hkls do not match for ome0, ome1!" # do etas -- ONLY COMPUTE IN CASE CONSISTENT REFERENCE COORDINATES if abs(np.dot(bHat_l.T, eHat_l)) < 1. - sqrt_epsf and np.any(goodOnes_s): eta0 = np.nan * np.ones_like(ome0) eta1 = np.nan * np.ones_like(ome1) # make eta basis COB with beam antiparallel with Z rMat_e = makeEtaFrameRotMat(bHat_l, eHat_l) goodOnes = np.tile(goodOnes_s, (1, 2)).flatten() numGood_s = sum(goodOnes_s) numGood = 2 * numGood_s tmp_eta = np.empty(numGood) tmp_gvec = np.tile(gHat_c, (1, 2))[:, goodOnes] allome = np.hstack([ome0, ome1]) for i in range(numGood): rMat_s = makeOscillRotMat([chi, allome[goodOnes][i]]) gVec_e = np.dot( rMat_e.T, np.dot(rMat_s, np.dot(rMat_c, tmp_gvec[:, i].reshape(3, 1)))) tmp_eta[i] = np.arctan2(gVec_e[1], gVec_e[0]) pass eta0[goodOnes_s] = tmp_eta[:numGood_s] eta1[goodOnes_s] = tmp_eta[numGood_s:] # make assoc tTh array tTh = 2. * np.arcsin(sintht).flatten() tTh0 = tTh tTh0[-goodOnes_s] = np.nan retval = ( np.vstack([tTh0.flatten(), eta0.flatten(), ome0.flatten()]), np.vstack([tTh0.flatten(), eta1.flatten(), ome1.flatten()]), ) else: retval = (ome0.flatten(), ome1.flatten()) pass return retval
def simulate_laue_pattern(self, crystal_data, minEnergy=5., maxEnergy=35., rmat_s=None, tvec_s=None, grain_params=None, beam_vec=None): """ """ if isinstance(crystal_data, PlaneData): plane_data = crystal_data # grab the expanded list of hkls from plane_data hkls = np.hstack(plane_data.getSymHKLs()) # and the unit plane normals (G-vectors) in CRYSTAL FRAME gvec_c = np.dot(plane_data.latVecOps['B'], hkls) elif len(crystal_data) == 2: # !!! should clean this up hkls = np.array(crystal_data[0]) bmat = crystal_data[1] gvec_c = np.dot(bmat, hkls) else: raise (RuntimeError, 'argument list not understood') nhkls_tot = hkls.shape[1] # parse energy ranges # TODO: allow for spectrum parsing 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(ct.keVToAngstrom(maxEnergy[i])) lmax.append(ct.keVToAngstrom(minEnergy[i])) else: lmin = ct.keVToAngstrom(maxEnergy) lmax = ct.keVToAngstrom(minEnergy) # parse grain parameters kwarg if grain_params is None: grain_params = np.atleast_2d( np.hstack([np.zeros(6), ct.identity_6x1])) n_grains = len(grain_params) # sample rotation if rmat_s is None: rmat_s = ct.identity_3x3 # dummy translation vector... make input if tvec_s is None: tvec_s = ct.zeros_3 # beam vector if beam_vec is None: beam_vec = ct.beam_vec # ========================================================================= # LOOP OVER GRAINS # ========================================================================= # 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)) for iG, gp in enumerate(grain_params): rmat_c = 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 gvec_s_str = np.dot(vInv_s, np.dot(rmat_c, gvec_c)) ghat_c_str = mutil.unitVector(np.dot(rmat_c.T, gvec_s_str)) # project dpts = gvecToDetectorXY(ghat_c_str.T, self.rmat, rmat_s, rmat_c, self.tvec, tvec_s, tvec_c, beamVec=beam_vec) # check intersections with detector plane canIntersect = ~np.isnan(dpts[:, 0]) npts_in = sum(canIntersect) if np.any(canIntersect): dpts = dpts[canIntersect, :].reshape(npts_in, 2) dhkl = hkls[:, canIntersect].reshape(3, npts_in) # back to angles tth_eta, gvec_l = detectorXYToGvec(dpts, self.rmat, rmat_s, self.tvec, tvec_s, tvec_c, beamVec=beam_vec) tth_eta = np.vstack(tth_eta).T # warp measured points if self.distortion is not None: if len(self.distortion) == 2: dpts = self.distortion[0](dpts, self.distortion[1], invert=True) else: raise (RuntimeError, "something is wrong with the distortion") # plane spacings and energies dsp = 1. / rowNorm(gvec_s_str[:, canIntersect].T) wlen = 2 * dsp * np.sin(0.5 * tth_eta[:, 0]) # clip to detector panel _, on_panel = self.clip_to_panel(dpts, buffer_edges=True) if multipleEnergyRanges: validEnergy = np.zeros(len(wlen), dtype=bool) for i in range(len(lmin)): in_energy_range = np.logical_and( wlen >= lmin[i], wlen <= lmax[i]) validEnergy = validEnergy | in_energy_range pass else: validEnergy = np.logical_and(wlen >= lmin, wlen <= lmax) pass # index for valid reflections keepers = np.where(np.logical_and(on_panel, validEnergy))[0] # assign output arrays xy_det[iG][keepers, :] = dpts[keepers, :] hkls_in[iG][:, keepers] = dhkl[:, keepers] angles[iG][keepers, :] = tth_eta[keepers, :] dspacing[iG, keepers] = dsp[keepers] energy[iG, keepers] = ct.keVToAngstrom(wlen[keepers]) pass # close conditional on valids pass # close loop on grains return xy_det, hkls_in, angles, dspacing, energy
def objFuncSX(pFit, pFull, pFlag, dFunc, dFlag, xyo_det, hkls_idx, bMat, vInv, bVec, eVec, omePeriod, simOnly=False, return_value_flag=return_value_flag): """ """ npts = len(xyo_det) refineFlag = np.array(np.hstack([pFlag, dFlag]), dtype=bool) print refineFlag # pFull[refineFlag] = pFit/scl[refineFlag] pFull[refineFlag] = pFit if dFunc is not None: dParams = pFull[-len(dFlag):] xys = dFunc(xyo_det[:, :2], dParams) else: xys = xyo_det[:, :2] # detector quantities wavelength = pFull[0] rMat_d = xf.makeDetectorRotMat(pFull[1:4]) tVec_d = pFull[4:7].reshape(3, 1) # sample quantities chi = pFull[7] tVec_s = pFull[8:11].reshape(3, 1) # crystal quantities rMat_c = xf.makeRotMatOfExpMap(pFull[11:14]) tVec_c = pFull[14:17].reshape(3, 1) # stretch tensor comp matrix from MV notation in SAMPLE frame vMat_s = mutil.vecMVToSymm(vInv) # g-vectors: # 1. calculate full g-vector components in CRYSTAL frame from B # 2. rotate into SAMPLE frame and apply stretch # 3. rotate back into CRYSTAL frame and normalize to unit magnitude # IDEA: make a function for this sequence of operations with option for # choosing ouput frame (i.e. CRYSTAL vs SAMPLE vs LAB) gVec_c = np.dot(bMat, hkls_idx) gVec_s = np.dot(vMat_s, np.dot(rMat_c, gVec_c)) gHat_c = mutil.unitVector(np.dot(rMat_c.T, gVec_s)) match_omes, calc_omes = matchOmegas(xyo_det, hkls_idx, chi, rMat_c, bMat, wavelength, vInv=vInv, beamVec=bVec, etaVec=eVec, omePeriod=omePeriod) calc_xy = np.zeros((npts, 2)) for i in range(npts): rMat_s = xfcapi.makeOscillRotMat([chi, calc_omes[i]]) calc_xy[i, :] = xfcapi.gvecToDetectorXY(gHat_c[:, i], rMat_d, rMat_s, rMat_c, tVec_d, tVec_s, tVec_c, beamVec=bVec).flatten() pass if np.any(np.isnan(calc_xy)): raise RuntimeError("infeasible pFull: may want to scale" + "back finite difference step size") # return values if simOnly: # return simulated values retval = np.hstack([calc_xy, calc_omes.reshape(npts, 1)]) else: # return residual vector # IDEA: try angles instead of xys? diff_vecs_xy = calc_xy - xys[:, :2] diff_ome = xf.angularDifference(calc_omes, xyo_det[:, 2]) retval = np.hstack([diff_vecs_xy, diff_ome.reshape(npts, 1)]).flatten() if return_value_flag == 1: # return scalar sum of squared residuals retval = sum(abs(retval)) elif return_value_flag == 2: # return DOF-normalized chisq # TODO: check this calculation denom = npts - len(pFit) - 1. if denom != 0: nu_fac = 1. / denom else: nu_fac = 1. nu_fac = 1 / (npts - len(pFit) - 1.) retval = nu_fac * sum(retval**2) return retval