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()
Example #2
0
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
Example #3
0
    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
Example #4
0
    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()
Example #5
0
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
Example #6
0
    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()
Example #7
0
    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
Example #8
0
    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
Example #9
0
    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()
Example #10
0
    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
Example #11
0
    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)
Example #12
0
    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)
Example #13
0
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
Example #14
0
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
Example #15
0
 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
Example #17
0
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
Example #18
0
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
Example #19
0
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
Example #20
0
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
Example #21
0
File: grains.py Project: cjh1/hexrd
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
Example #22
0
 def get_e_mat(self, grain_params):
     # TODO: document what is this?
     return logm(np.linalg.inv(vecMVToSymm(grain_params[6:])))
Example #23
0
 def get_e_mat(self, grain_params):
     """
     strain tensor calculation
     """
     return logm(np.linalg.inv(vecMVToSymm(grain_params[6:])))
Example #24
0
    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
Example #25
0
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
Example #26
0
                    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()
Example #28
0
 def get_e_mat(self, grain_params):
     # TODO: document what is this?
     return logm(np.linalg.inv(vecMVToSymm(grain_params[6:])))
Example #29
0
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
Example #30
0
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
Example #31
0
    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
Example #32
0
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