Пример #1
0
def writeGVE(spotsArray, fileroot, **kwargs):
    """
    write Fable gve file from Spots object

    fileroot is the root string used to write the gve and ini files

    Outputs:

    No return value, but writes the following files:

    <fileroot>.gve
    <fileroot>_grainSpotter.ini (points to --> <fileroot>_grainSpotter.log)

    Keyword arguments:

    Mainly for GrainSpotter .ini file, but some are needed for gve files

    keyword        default              definitions
    -----------------------------------------------------------------------------------------
    'sgNum':       <225>
    'phaseID':     <None>
    'cellString':  <F>
    'omeRange':    <-60, 60, 120, 240>  the oscillation range(s) **currently pulls from spots
    'deltaOme':    <0.25, 0.25>         the oscillation delta(s) **currently pulls from spots
    'minMeas':     <24>
    'minCompl':    <0.7>
    'minUniqn':    <0.5>
    'uncertainty': <[0.10, 0.25, .50]>  the min [tTh, eta, ome] uncertainties in degrees
    'eulStep':     <2>
    'nSigmas':     <2>
    'minFracG':    <0.90>
    'nTrials':     <100000>
    'positionfit': <True>

    Notes:

    *) The omeRange is currently pulled from the spotsArray input; the kwarg has no effect
       as of now.  Will change this to 'override' the spots info if the user, say, wants to
       pare down the range.

    *) There is no etaRange argument yet, but presumably GrainSpotter knows how to deal
       with this.  Pending feature...
    """
    # check on fileroot
    assert isinstance(fileroot, str)

    # keyword argument processing
    phaseID     = None
    sgNum       = 225
    cellString  = 'P'
    omeRange    = num.r_[-60, 60]   # in DEGREES
    deltaOme    = 0.25              # in DEGREES
    minMeas     = 24
    minCompl    = 0.7
    minUniqn    = 0.5
    uncertainty = [0.10, 0.25, .50] # in DEGREES
    eulStep     = 2                 # in DEGREES
    nSigmas     = 2
    minFracG    = 0.90
    numTrials   = 100000
    positionFit = True

    kwarglen = len(kwargs)
    if kwarglen > 0:
        argkeys = kwargs.keys()
        for i in range(kwarglen):
            if argkeys[i] == 'sgNum':
                sgNum = kwargs[argkeys[i]]
            elif argkeys[i] == 'phaseID':
                phaseID = kwargs[argkeys[i]]
            elif argkeys[i] == 'cellString':
                cellString = kwargs[argkeys[i]]
            elif argkeys[i] == 'omeRange':
                omeRange = kwargs[argkeys[i]]
            elif argkeys[i] == 'deltaOme':
                deltaOme = kwargs[argkeys[i]]
            elif argkeys[i] == 'minMeas':
                minMeas = kwargs[argkeys[i]]
            elif argkeys[i] == 'minCompl':
                minCompl = kwargs[argkeys[i]]
            elif argkeys[i] == 'minUniqn':
                minUniqn = kwargs[argkeys[i]]
            elif argkeys[i] == 'uncertainty':
                uncertainty = kwargs[argkeys[i]]
            elif argkeys[i] == 'eulStep':
                eulStep = kwargs[argkeys[i]]
            elif argkeys[i] == 'nSigmas':
                nSigmas = kwargs[argkeys[i]]
            elif argkeys[i] == 'minFracG':
                minFracG = kwargs[argkeys[i]]
            elif argkeys[i] == 'nTrials':
                numTrials = kwargs[argkeys[i]]
            elif argkeys[i] == 'positionfit':
                positionFit = kwargs[argkeys[i]]
            else:
                raise RuntimeError, "Unrecognized keyword argument '%s'" % (argkeys[i])

    # grab some detector geometry parameters for gve file header
    mmPerPixel = float(spotsArray.detectorGeom.pixelPitch) # ...these are still hard-coded to be square
    nrows_p = spotsArray.detectorGeom.nrows - 1
    ncols_p = spotsArray.detectorGeom.ncols - 1

    row_p, col_p = spotsArray.detectorGeom.pixelIndicesOfCartesianCoords(spotsArray.detectorGeom.xc,
                                                                         spotsArray.detectorGeom.yc)
    yc_p = ncols_p - col_p
    zc_p = nrows_p - row_p

    wd_mu = spotsArray.detectorGeom.workDist * 1e3 # in microns (Soeren)

    osc_axis = num.dot(fableSampCOB.T, Yl).flatten()

    # start grabbing stuff from planeData
    planeData = spotsArray.getPlaneData(phaseID=phaseID)
    cellp   = planeData.latVecOps['dparms']
    U0      = planeData.latVecOps['U0']
    wlen    = planeData.wavelength
    dsp     = planeData.getPlaneSpacings()
    fHKLs   = planeData.getSymHKLs()
    tThRng  = planeData.getTThRanges()
    symTag  = planeData.getLaueGroup()

    tThMin, tThMax = (r2d*tThRng.min(), r2d*tThRng.max()) # single range should be ok since entering hkls
    etaMin, etaMax = (0, 360)   # not sure when this will ever *NOT* be the case, so setting it

    omeMin = spotsArray.getOmegaMins()
    omeMax = spotsArray.getOmegaMaxs()

    omeRangeString = ''
    for iOme in range(len(omeMin)):
        if hasattr(omeMin[iOme], 'getVal'):
            omeRangeString += 'omegarange %g %g\n' % (omeMin[iOme].getVal('degrees'), omeMax[iOme].getVal('degrees'))
        else:
            omeRangeString += 'omegarange %g %g\n' % (omeMin[iOme] * r2d, omeMax[iOme] * r2d)

    # convert angles
    cellp[3:] = r2d*cellp[3:]

    # make the theoretical hkls string
    gvecHKLString = ''
    for i in range(len(dsp)):
        for j in range(fHKLs[i].shape[1]):
            gvecHKLString += '%1.8f %d %d %d\n' % (1/dsp[i], fHKLs[i][0, j], fHKLs[i][1, j], fHKLs[i][2, j])

    # now for the measured data section
    # xr yr zr xc yc ds eta omega
    gvecString = ''
    spotsIter = spotsArray.getIterPhase(phaseID, returnBothCoordTypes=True)
    for iSpot, angCOM, xyoCOM in spotsIter:
        sR, sC, sOme     = xyoCOM                          # detector coords
        sTTh, sEta, sOme = angCOM                          # angular coords (radians)
        sDsp = wlen / 2. / num.sin(0.5*sTTh)               # dspacing

        # get raw y, z (Fable frame)
        yraw = ncols_p - sC
        zraw = nrows_p - sR

        # convert eta to fable frame
        rEta = mapAngle(90. - r2d*sEta, [0, 360], units='degrees')

        # make mesaured G vector components in fable frame
        mGvec = makeMeasuredScatteringVectors(sTTh, sEta, sOme, convention='fable', frame='sample')

        # full Gvec components in fable lab frame (for grainspotter position fit)
        gveXYZ = spotsArray.detectorGeom.angToXYO(sTTh, sEta, sOme, outputGve=True)

        # no 4*pi
        mGvec = mGvec / sDsp

        # make contribution
        gvecString += '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %d %1.8f %1.8f %1.8f\n' \
                      % (mGvec[0], mGvec[1], mGvec[2], \
                         sR, sC,  \
                         1/sDsp, rEta, r2d*sOme, \
                         iSpot, \
                         gveXYZ[0, :], gveXYZ[1, :], gveXYZ[2, :])
        pass

    # write gve file for grainspotter
    fid = open(fileroot+'.gve', 'w')
    print >> fid, '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f ' % tuple(cellp)        + \
          cellString + '\n'                                                    + \
          '# wavelength = %1.8f\n'                       % (wlen)              + \
          '# wedge = 0.000000\n'                                               + \
          '# axis = %d %d %d\n'                          % tuple(osc_axis)     + \
          '# cell__a %1.4f\n'                            %(cellp[0])           + \
          '# cell__b %1.4f\n'                            %(cellp[1])           + \
          '# cell__c %1.4f\n'                            %(cellp[2])           + \
          '# cell_alpha %1.4f\n'                         %(cellp[3])           + \
          '# cell_beta  %1.4f\n'                         %(cellp[4])           + \
          '# cell_gamma %1.4f\n'                         %(cellp[5])           + \
          '# cell_lattice_[P,A,B,C,I,F,R] %s\n'          %(cellString)         + \
          '# chi 0.0\n'                                                        + \
          '# distance %.4f\n'                            %(wd_mu)              + \
          '# fit_tolerance 0.5\n'                                              + \
          '# o11  1\n'                                                         + \
          '# o12  0\n'                                                         + \
          '# o21  0\n'                                                         + \
          '# o22 -1\n'                                                         + \
          '# omegasign %1.1f\n'                          %(num.sign(deltaOme)) + \
          '# t_x 0\n'                                                          + \
          '# t_y 0\n'                                                          + \
          '# t_z 0\n'                                                          + \
          '# tilt_x 0.000000\n'                                                + \
          '# tilt_y 0.000000\n'                                                + \
          '# tilt_z 0.000000\n'                                                + \
          '# y_center %.6f\n'                            %(yc_p)               + \
          '# y_size %.6f\n'                              %(mmPerPixel*1.e3)    + \
          '# z_center %.6f\n'                            %(zc_p)               + \
          '# z_size %.6f\n'                              %(mmPerPixel*1.e3)    + \
          '# ds h k l\n'                                                       + \
          gvecHKLString                                                        + \
          '# xr yr zr xc yc ds eta omega\n'                                    + \
          gvecString
    fid.close()

    ###############################################################
    # GrainSpotter ini parameters
    #
    # fileroot = tempfile.mktemp()
    if positionFit:
        positionString = 'positionfit'
    else:
        positionString = '!positionfit'

    if numTrials == 0:
        randomString = '!random\n'
    else:
        randomString = 'random %g\n' % (numTrials)

    fid = open(fileroot+'_grainSpotter.ini', 'w')
    # self.__tempFNameList.append(fileroot)
    print >> fid, \
          'spacegroup %d\n' % (sgNum) + \
          'tthrange %g %g\n' % (tThMin, tThMax) + \
          'etarange %g %g\n' % (etaMin, etaMax) + \
          'domega %g\n' % (deltaOme) + \
          omeRangeString + \
          'filespecs %s.gve %s_grainSpotter.log\n' % (fileroot, fileroot) + \
          'cuts %d %g %g\n' % (minMeas, minCompl, minUniqn) + \
          'eulerstep %g\n' % (eulStep)+ \
          'uncertainties %g %g %g\n' % (uncertainty[0], uncertainty[1], uncertainty[2]) + \
          'nsigmas %d\n' % (nSigmas) + \
          'minfracg %g\n' % (minFracG) + \
          randomString + \
          positionString + '\n'
    fid.close()
    return
Пример #2
0
def getFriedelPair(tth0, eta0, *ome0, **kwargs):
    """
    Get the diffractometer angular coordinates in degrees for
    the Friedel pair of a given reflection (min angular distance).

    AUTHORS:

    J. V. Bernier -- 10 Nov 2009

    USAGE:

    ome1, eta1 = getFriedelPair(tth0, eta0, *ome0,
                                display=False,
                                units='degrees',
                                convention='hexrd')

    INPUTS:

    1) tth0 is a list (or ndarray) of 1 or n the bragg angles (2theta) for
       the n reflections (tiled to match eta0 if only 1 is given).

    2) eta0 is a list (or ndarray) of 1 or n azimuthal coordinates for the n
       reflections  (tiled to match tth0 if only 1 is given).

    3) ome0 is a list (or ndarray) of 1 or n reference oscillation
       angles for the n reflections (denoted omega in [1]).  This argument
       is optional.

    4) Keyword arguments may be one of the following:

    Keyword             Values|{default}        Action
    --------------      --------------          --------------
    'display'           True|{False}            toggles display info to cmd line
    'units'             'radians'|{'degrees'}   sets units for input angles
    'convention'        'fable'|{'hexrd'}         sets conventions defining
                                                the angles (see below)
    'chiTilt'           None                    the inclination (about Xlab) of
                                                the oscillation axis

    OUTPUTS:

    1) ome1 contains the oscialltion angle coordinates of the
       Friedel pairs associated with the n input reflections, relative to ome0
       (i.e. ome1 = <result> + ome0).  Output is in DEGREES!

    2) eta1 contains the azimuthal coordinates of the Friedel
       pairs associated with the n input reflections.  Output units are
       controlled via the module variable 'outputDegrees'

    NOTES:

    JVB) The ouputs ome1, eta1 are written using the selected convention, but the
         units are alway degrees.  May change this to work with Nathan's global...

    JVB) In the 'fable' convention [1], {XYZ} form a RHON basis where X is
         downstream, Z is vertical, and eta is CCW with +Z defining eta = 0.

    JVB) In the 'hexrd' convention [2], {XYZ} form a RHON basis where Z is upstream,
         Y is vertical, and eta is CCW with +X defining eta = 0.

    REFERENCES:

    [1] E. M. Lauridsen, S. Schmidt, R. M. Suter, and H. F. Poulsen,
        ``Tracking: a method for structural characterization of grains in
        powders or polycrystals''. J. Appl. Cryst. (2001). 34, 744--750

    [2] J. V. Bernier, M. P. Miller, J. -S. Park, and U. Lienert,
        ``Quantitative Stress Analysis of Recrystallized OFHC Cu Subject
        to Deformed In Situ'', J. Eng. Mater. Technol. (2008). 130.
        DOI:10.1115/1.2870234
    """

    dispFlag = False
    fableFlag = False
    chi = None
    c1 = 1.0
    c2 = pi / 180.0
    zTol = 1.0e-7

    # cast to arrays (in case they aren't)
    if num.isscalar(eta0):
        eta0 = [eta0]

    if num.isscalar(tth0):
        tth0 = [tth0]

    if num.isscalar(ome0):
        ome0 = [ome0]

    eta0 = num.asarray(eta0)
    tth0 = num.asarray(tth0)
    ome0 = num.asarray(ome0)

    if eta0.ndim != 1:
        raise RuntimeError, "your azimuthal input was not 1-D, so I do not know what you expect me to do"

    npts = len(eta0)

    if tth0.ndim != 1:
        raise RuntimeError, "your Bragg angle input was not 1-D, so I do not know what you expect me to do"
    else:
        if len(tth0) != npts:
            if len(tth0) == 1:
                tth0 = tth0 * num.ones(npts)
            elif npts == 1:
                npts = len(tth0)
                eta0 = eta0 * num.ones(npts)
            else:
                raise RuntimeError, "the azimuthal and Bragg angle inputs are inconsistent"

    if len(ome0) == 0:
        ome0 = num.zeros(npts)  # dummy ome0
    elif len(ome0) == 1 and npts > 1:
        ome0 = ome0 * num.ones(npts)
    else:
        if len(ome0) != npts:
            raise RuntimeError(
                "your oscialltion angle input is inconsistent; "
                + "it has length %d while it should be %d" % (len(ome0), npts)
            )

    # keyword args processing
    kwarglen = len(kwargs)
    if kwarglen > 0:
        argkeys = kwargs.keys()
        for i in range(kwarglen):
            if argkeys[i] == "display":
                dispFlag = kwargs[argkeys[i]]
            elif argkeys[i] == "convention":
                if kwargs[argkeys[i]].lower() == "fable":
                    fableFlag = True
            elif argkeys[i] == "units":
                if kwargs[argkeys[i]] == "radians":
                    c1 = 180.0 / pi
                    c2 = 1.0
            elif argkeys[i] == "chiTilt":
                if kwargs[argkeys[i]] is not None:
                    chi = kwargs[argkeys[i]]

    # a little talkback...
    if dispFlag:
        if fableFlag:
            print "\nUsing Fable angle convention\n"
        else:
            print "\nUsing image-based angle convention\n"

    # mapped eta input
    #   - in DEGREES, thanks to c1
    eta0 = mapAngle(c1 * eta0, [-180, 180], units="degrees")
    if fableFlag:
        eta0 = 90 - eta0

    # must put args into RADIANS
    #   - eta0 is in DEGREES,
    #   - the others are in whatever was entered, hence c2
    eta0 = d2r * eta0
    tht0 = c2 * tth0 / 2
    if chi is not None:
        chi = c2 * chi
    else:
        chi = 0

    # ---------------------
    # SYSTEM SOLVE
    #
    #
    # cos(chi)cos(eta)cos(theta)sin(x) - cos(chi)sin(theta)cos(x) = sin(theta) - sin(chi)sin(eta)cos(theta)
    #
    #
    # Identity: a sin x + b cos x = sqrt(a**2 + b**2) sin (x + alfa)
    #
    #       /
    #       |      atan(b/a) for a > 0
    # alfa <
    #       | pi + atan(b/a) for a < 0
    #       \
    #
    # => sin (x + alfa) = c / sqrt(a**2 + b**2)
    #
    # must use both branches for sin(x) = n: x = u (+ 2k*pi) | x = pi - u (+ 2k*pi)
    #
    cchi = num.cos(chi)
    schi = num.sin(chi)
    ceta = num.cos(eta0)
    seta = num.sin(eta0)
    ctht = num.cos(tht0)
    stht = num.sin(tht0)

    nchi = num.c_[0.0, cchi, schi].T

    gHat0_l = -num.vstack([ceta * ctht, seta * ctht, stht])

    a = cchi * ceta * ctht
    b = -cchi * stht
    c = stht + schi * seta * ctht

    # form solution
    abMag = num.sqrt(a * a + b * b)
    assert num.all(abMag > 0), "Beam vector specification is infeasible!"
    phaseAng = num.arctan2(b, a)
    rhs = c / abMag
    rhs[abs(rhs) > 1.0] = num.nan
    rhsAng = num.arcsin(rhs)

    # write ome angle output arrays (NaNs persist here)
    ome1 = rhsAng - phaseAng
    ome2 = num.pi - rhsAng - phaseAng

    ome1 = mapAngle(ome1, [-num.pi, num.pi], units="radians")
    ome2 = mapAngle(ome2, [-num.pi, num.pi], units="radians")

    ome_stack = num.vstack([ome1, ome2])

    min_idx = num.argmin(abs(ome_stack), axis=0)

    ome_min = ome_stack[min_idx, range(len(ome1))]
    eta_min = num.nan * num.ones_like(ome_min)

    # mark feasible reflections
    goodOnes = -num.isnan(ome_min)

    numGood = sum(goodOnes)
    tmp_eta = num.empty(numGood)
    tmp_gvec = gHat0_l[:, goodOnes]
    for i in range(numGood):
        come = num.cos(ome_min[goodOnes][i])
        some = num.sin(ome_min[goodOnes][i])
        rchi = rotMatOfExpMap(num.tile(ome_min[goodOnes][i], (3, 1)) * nchi)
        gHat_l = num.dot(rchi, tmp_gvec[:, i].reshape(3, 1))
        tmp_eta[i] = num.arctan2(gHat_l[1], gHat_l[0])
        pass
    eta_min[goodOnes] = tmp_eta

    # everybody back to DEGREES!
    #     - ome1 is in RADIANS here
    #     - convert and put into [-180, 180]
    ome1 = mapAngle(mapAngle(r2d * ome_min, [-180, 180], units="degrees") + c1 * ome0, [-180, 180], units="degrees")

    # put eta1 in [-180, 180]
    eta1 = mapAngle(r2d * eta_min, [-180, 180], units="degrees")

    if not outputDegrees:
        ome1 = d2r * ome1
        eta1 = d2r * eta1

    return ome1, eta1
set12 = eta0 > 90.0

lw = 2
fig1 = plt.figure(1)
fig1.clf()
axes1 = fig1.gca()
fig2 = plt.figure(2)
fig2.clf()
axes2 = fig2.gca()
for i in range(len(chi)):
    ome1, eta1 = xtl.getFriedelPair(tth0, eta0, chiTilt=chi[i], units="degrees", convention="hexrd")
    axes1.plot(d2r * eta0[set11], ome1[set11], lt[i], label="$\chi$=%d$^\circ$" % chi[i], linewidth=lw)
    axes1.plot(d2r * eta0[set12], ome1[set12], lt[i], label="$\chi$=%d$^\circ$" % chi[i], linewidth=lw)

    # eta = np.pi - rot.angularDifference(d2r*eta0, eta1)
    eta = rot.mapAngle(np.pi - (d2r * eta0 - eta1))
    set1 = np.logical_and(eta0 <= 0.0, eta >= 0.0)
    set2 = np.logical_and(eta0 <= 0.0, eta <= 0.0)
    set3 = eta0 >= 0.0

    axes2.plot(d2r * eta0, eta, lt[i], linewidth=lw)
    # axes2.plot(d2r*eta0[set1], eta[set1], lt[i], linewidth=lw)
    # axes2.plot(d2r*eta0[set2], eta[set2], lt[i], linewidth=lw)
    # axes2.plot(d2r*eta0[set3], eta[set3], lt[i], linewidth=lw)

axes1.grid(True)
axes1.axis("tight")

axes1.set_xlabel("starting azimuth, $\eta_0$")
axes1.set_ylabel("minimum $\Delta\omega_{FP}$")
Пример #4
0
def writeGVE(spotsArray, fileroot, **kwargs):
    """
    write Fable gve file from Spots object

    fileroot is the root string used to write the gve and ini files

    Outputs:

    No return value, but writes the following files:

    <fileroot>.gve
    <fileroot>_grainSpotter.ini (points to --> <fileroot>_grainSpotter.log)

    Keyword arguments:

    Mainly for GrainSpotter .ini file, but some are needed for gve files

    keyword        default              definitions
    -----------------------------------------------------------------------------------------
    'sgNum':       <225>
    'phaseID':     <None>
    'cellString':  <F>
    'omeRange':    <-60, 60, 120, 240>  the oscillation range(s) **currently pulls from spots
    'deltaOme':    <0.25, 0.25>         the oscillation delta(s) **currently pulls from spots
    'minMeas':     <24>
    'minCompl':    <0.7>
    'minUniqn':    <0.5>
    'uncertainty': <[0.10, 0.25, .50]>  the min [tTh, eta, ome] uncertainties in degrees
    'eulStep':     <2>
    'nSigmas':     <2>
    'minFracG':    <0.90>
    'nTrials':     <100000>
    'positionfit': <True>

    Notes:

    *) The omeRange is currently pulled from the spotsArray input; the kwarg has no effect
       as of now.  Will change this to 'override' the spots info if the user, say, wants to
       pare down the range.

    *) There is no etaRange argument yet, but presumably GrainSpotter knows how to deal
       with this.  Pending feature...
    """
    # check on fileroot
    assert isinstance(fileroot, str)

    # keyword argument processing
    phaseID = None
    sgNum = 225
    cellString = 'P'
    omeRange = num.r_[-60, 60]  # in DEGREES
    deltaOme = 0.25  # in DEGREES
    minMeas = 24
    minCompl = 0.7
    minUniqn = 0.5
    uncertainty = [0.10, 0.25, .50]  # in DEGREES
    eulStep = 2  # in DEGREES
    nSigmas = 2
    minFracG = 0.90
    numTrials = 100000
    positionFit = True

    kwarglen = len(kwargs)
    if kwarglen > 0:
        argkeys = kwargs.keys()
        for i in range(kwarglen):
            if argkeys[i] == 'sgNum':
                sgNum = kwargs[argkeys[i]]
            elif argkeys[i] == 'phaseID':
                phaseID = kwargs[argkeys[i]]
            elif argkeys[i] == 'cellString':
                cellString = kwargs[argkeys[i]]
            elif argkeys[i] == 'omeRange':
                omeRange = kwargs[argkeys[i]]
            elif argkeys[i] == 'deltaOme':
                deltaOme = kwargs[argkeys[i]]
            elif argkeys[i] == 'minMeas':
                minMeas = kwargs[argkeys[i]]
            elif argkeys[i] == 'minCompl':
                minCompl = kwargs[argkeys[i]]
            elif argkeys[i] == 'minUniqn':
                minUniqn = kwargs[argkeys[i]]
            elif argkeys[i] == 'uncertainty':
                uncertainty = kwargs[argkeys[i]]
            elif argkeys[i] == 'eulStep':
                eulStep = kwargs[argkeys[i]]
            elif argkeys[i] == 'nSigmas':
                nSigmas = kwargs[argkeys[i]]
            elif argkeys[i] == 'minFracG':
                minFracG = kwargs[argkeys[i]]
            elif argkeys[i] == 'nTrials':
                numTrials = kwargs[argkeys[i]]
            elif argkeys[i] == 'positionfit':
                positionFit = kwargs[argkeys[i]]
            else:
                raise RuntimeError, "Unrecognized keyword argument '%s'" % (
                    argkeys[i])

    # grab some detector geometry parameters for gve file header
    mmPerPixel = float(spotsArray.detectorGeom.pixelPitch
                       )  # ...these are still hard-coded to be square
    nrows_p = spotsArray.detectorGeom.nrows - 1
    ncols_p = spotsArray.detectorGeom.ncols - 1

    row_p, col_p = spotsArray.detectorGeom.pixelIndicesOfCartesianCoords(
        spotsArray.detectorGeom.xc, spotsArray.detectorGeom.yc)
    yc_p = ncols_p - col_p
    zc_p = nrows_p - row_p

    wd_mu = spotsArray.detectorGeom.workDist * 1e3  # in microns (Soeren)

    osc_axis = num.dot(fableSampCOB.T, Yl).flatten()

    # start grabbing stuff from planeData
    planeData = spotsArray.getPlaneData(phaseID=phaseID)
    cellp = planeData.latVecOps['dparms']
    U0 = planeData.latVecOps['U0']
    wlen = planeData.wavelength
    dsp = planeData.getPlaneSpacings()
    fHKLs = planeData.getSymHKLs()
    tThRng = planeData.getTThRanges()
    symTag = planeData.getLaueGroup()

    tThMin, tThMax = (r2d * tThRng.min(), r2d * tThRng.max()
                      )  # single range should be ok since entering hkls
    etaMin, etaMax = (
        0, 360
    )  # not sure when this will ever *NOT* be the case, so setting it

    omeMin = spotsArray.getOmegaMins()
    omeMax = spotsArray.getOmegaMaxs()

    omeRangeString = ''
    for iOme in range(len(omeMin)):
        if hasattr(omeMin[iOme], 'getVal'):
            omeRangeString += 'omegarange %g %g\n' % (
                omeMin[iOme].getVal('degrees'), omeMax[iOme].getVal('degrees'))
        else:
            omeRangeString += 'omegarange %g %g\n' % (omeMin[iOme] * r2d,
                                                      omeMax[iOme] * r2d)

    # convert angles
    cellp[3:] = r2d * cellp[3:]

    # make the theoretical hkls string
    gvecHKLString = ''
    for i in range(len(dsp)):
        for j in range(fHKLs[i].shape[1]):
            gvecHKLString += '%1.8f %d %d %d\n' % (
                1 / dsp[i], fHKLs[i][0, j], fHKLs[i][1, j], fHKLs[i][2, j])

    # now for the measured data section
    # xr yr zr xc yc ds eta omega
    gvecString = ''
    spotsIter = spotsArray.getIterPhase(phaseID, returnBothCoordTypes=True)
    for iSpot, angCOM, xyoCOM in spotsIter:
        sR, sC, sOme = xyoCOM  # detector coords
        sTTh, sEta, sOme = angCOM  # angular coords (radians)
        sDsp = wlen / 2. / num.sin(0.5 * sTTh)  # dspacing

        # get raw y, z (Fable frame)
        yraw = ncols_p - sC
        zraw = nrows_p - sR

        # convert eta to fable frame
        rEta = mapAngle(90. - r2d * sEta, [0, 360], units='degrees')

        # make mesaured G vector components in fable frame
        mGvec = makeMeasuredScatteringVectors(sTTh,
                                              sEta,
                                              sOme,
                                              convention='fable',
                                              frame='sample')

        # full Gvec components in fable lab frame (for grainspotter position fit)
        gveXYZ = spotsArray.detectorGeom.angToXYO(sTTh,
                                                  sEta,
                                                  sOme,
                                                  outputGve=True)

        # no 4*pi
        mGvec = mGvec / sDsp

        # make contribution
        gvecString += '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %d %1.8f %1.8f %1.8f\n' \
                      % (mGvec[0], mGvec[1], mGvec[2], \
                         sR, sC,  \
                         1/sDsp, rEta, r2d*sOme, \
                         iSpot, \
                         gveXYZ[0, :], gveXYZ[1, :], gveXYZ[2, :])
        pass

    # write gve file for grainspotter
    fid = open(fileroot + '.gve', 'w')
    print >> fid, '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f ' % tuple(cellp)        + \
          cellString + '\n'                                                    + \
          '# wavelength = %1.8f\n'                       % (wlen)              + \
          '# wedge = 0.000000\n'                                               + \
          '# axis = %d %d %d\n'                          % tuple(osc_axis)     + \
          '# cell__a %1.4f\n'                            %(cellp[0])           + \
          '# cell__b %1.4f\n'                            %(cellp[1])           + \
          '# cell__c %1.4f\n'                            %(cellp[2])           + \
          '# cell_alpha %1.4f\n'                         %(cellp[3])           + \
          '# cell_beta  %1.4f\n'                         %(cellp[4])           + \
          '# cell_gamma %1.4f\n'                         %(cellp[5])           + \
          '# cell_lattice_[P,A,B,C,I,F,R] %s\n'          %(cellString)         + \
          '# chi 0.0\n'                                                        + \
          '# distance %.4f\n'                            %(wd_mu)              + \
          '# fit_tolerance 0.5\n'                                              + \
          '# o11  1\n'                                                         + \
          '# o12  0\n'                                                         + \
          '# o21  0\n'                                                         + \
          '# o22 -1\n'                                                         + \
          '# omegasign %1.1f\n'                          %(num.sign(deltaOme)) + \
          '# t_x 0\n'                                                          + \
          '# t_y 0\n'                                                          + \
          '# t_z 0\n'                                                          + \
          '# tilt_x 0.000000\n'                                                + \
          '# tilt_y 0.000000\n'                                                + \
          '# tilt_z 0.000000\n'                                                + \
          '# y_center %.6f\n'                            %(yc_p)               + \
          '# y_size %.6f\n'                              %(mmPerPixel*1.e3)    + \
          '# z_center %.6f\n'                            %(zc_p)               + \
          '# z_size %.6f\n'                              %(mmPerPixel*1.e3)    + \
          '# ds h k l\n'                                                       + \
          gvecHKLString                                                        + \
          '# xr yr zr xc yc ds eta omega\n'                                    + \
          gvecString
    fid.close()

    ###############################################################
    # GrainSpotter ini parameters
    #
    # fileroot = tempfile.mktemp()
    if positionFit:
        positionString = 'positionfit'
    else:
        positionString = '!positionfit'

    if numTrials == 0:
        randomString = '!random\n'
    else:
        randomString = 'random %g\n' % (numTrials)

    fid = open(fileroot + '_grainSpotter.ini', 'w')
    # self.__tempFNameList.append(fileroot)
    print >> fid, \
          'spacegroup %d\n' % (sgNum) + \
          'tthrange %g %g\n' % (tThMin, tThMax) + \
          'etarange %g %g\n' % (etaMin, etaMax) + \
          'domega %g\n' % (deltaOme) + \
          omeRangeString + \
          'filespecs %s.gve %s_grainSpotter.log\n' % (fileroot, fileroot) + \
          'cuts %d %g %g\n' % (minMeas, minCompl, minUniqn) + \
          'eulerstep %g\n' % (eulStep)+ \
          'uncertainties %g %g %g\n' % (uncertainty[0], uncertainty[1], uncertainty[2]) + \
          'nsigmas %d\n' % (nSigmas) + \
          'minfracg %g\n' % (minFracG) + \
          randomString + \
          positionString + '\n'
    fid.close()
    return
Пример #5
0
def getFriedelPair(tth0, eta0, *ome0, **kwargs):
    """
    Get the diffractometer angular coordinates in degrees for
    the Friedel pair of a given reflection (min angular distance).

    AUTHORS:

    J. V. Bernier -- 10 Nov 2009

    USAGE:

    ome1, eta1 = getFriedelPair(tth0, eta0, *ome0,
                                display=False,
                                units='degrees',
                                convention='hexrd')

    INPUTS:

    1) tth0 is a list (or ndarray) of 1 or n the bragg angles (2theta) for
       the n reflections (tiled to match eta0 if only 1 is given).

    2) eta0 is a list (or ndarray) of 1 or n azimuthal coordinates for the n
       reflections  (tiled to match tth0 if only 1 is given).

    3) ome0 is a list (or ndarray) of 1 or n reference oscillation
       angles for the n reflections (denoted omega in [1]).  This argument
       is optional.

    4) Keyword arguments may be one of the following:

    Keyword             Values|{default}        Action
    --------------      --------------          --------------
    'display'           True|{False}            toggles display info to cmd line
    'units'             'radians'|{'degrees'}   sets units for input angles
    'convention'        'fable'|{'hexrd'}         sets conventions defining
                                                the angles (see below)
    'chiTilt'           None                    the inclination (about Xlab) of
                                                the oscillation axis

    OUTPUTS:

    1) ome1 contains the oscialltion angle coordinates of the
       Friedel pairs associated with the n input reflections, relative to ome0
       (i.e. ome1 = <result> + ome0).  Output is in DEGREES!

    2) eta1 contains the azimuthal coordinates of the Friedel
       pairs associated with the n input reflections.  Output units are
       controlled via the module variable 'outputDegrees'

    NOTES:

    JVB) The ouputs ome1, eta1 are written using the selected convention, but the
         units are alway degrees.  May change this to work with Nathan's global...

    JVB) In the 'fable' convention [1], {XYZ} form a RHON basis where X is
         downstream, Z is vertical, and eta is CCW with +Z defining eta = 0.

    JVB) In the 'hexrd' convention [2], {XYZ} form a RHON basis where Z is upstream,
         Y is vertical, and eta is CCW with +X defining eta = 0.

    REFERENCES:

    [1] E. M. Lauridsen, S. Schmidt, R. M. Suter, and H. F. Poulsen,
        ``Tracking: a method for structural characterization of grains in
        powders or polycrystals''. J. Appl. Cryst. (2001). 34, 744--750

    [2] J. V. Bernier, M. P. Miller, J. -S. Park, and U. Lienert,
        ``Quantitative Stress Analysis of Recrystallized OFHC Cu Subject
        to Deformed In Situ'', J. Eng. Mater. Technol. (2008). 130.
        DOI:10.1115/1.2870234
    """

    dispFlag  = False
    fableFlag = False
    chi       = None
    c1        = 1.
    c2        = pi/180.
    zTol      = 1.e-7

    # cast to arrays (in case they aren't)
    if num.isscalar(eta0):
        eta0 = [eta0]

    if num.isscalar(tth0):
        tth0 = [tth0]

    if num.isscalar(ome0):
        ome0 = [ome0]

    eta0 = num.asarray(eta0)
    tth0 = num.asarray(tth0)
    ome0 = num.asarray(ome0)

    if eta0.ndim != 1:
        raise RuntimeError, 'your azimuthal input was not 1-D, so I do not know what you expect me to do'

    npts = len(eta0)

    if tth0.ndim != 1:
        raise RuntimeError, 'your Bragg angle input was not 1-D, so I do not know what you expect me to do'
    else:
        if len(tth0) != npts:
            if len(tth0) == 1:
                tth0 = tth0*num.ones(npts)
            elif npts == 1:
                npts = len(tth0)
                eta0 = eta0*num.ones(npts)
            else:
                raise RuntimeError, 'the azimuthal and Bragg angle inputs are inconsistent'

    if len(ome0) == 0:
        ome0 = num.zeros(npts)                  # dummy ome0
    elif len(ome0) == 1 and npts > 1:
        ome0 = ome0*num.ones(npts)
    else:
        if len(ome0) != npts:
            raise RuntimeError('your oscialltion angle input is inconsistent; ' \
                               + 'it has length %d while it should be %d' % (len(ome0), npts) )

    # keyword args processing
    kwarglen = len(kwargs)
    if kwarglen > 0:
        argkeys = kwargs.keys()
        for i in range(kwarglen):
            if argkeys[i] == 'display':
                dispFlag = kwargs[argkeys[i]]
            elif argkeys[i] == 'convention':
                if kwargs[argkeys[i]].lower() == 'fable':
                    fableFlag = True
            elif argkeys[i] == 'units':
                if kwargs[argkeys[i]] == 'radians':
                    c1 = 180./pi
                    c2 = 1.
            elif argkeys[i] == 'chiTilt':
                if kwargs[argkeys[i]] is not None:
                    chi = kwargs[argkeys[i]]

    # a little talkback...
    if dispFlag:
        if fableFlag:
            print '\nUsing Fable angle convention\n'
        else:
            print '\nUsing image-based angle convention\n'

    # mapped eta input
    #   - in DEGREES, thanks to c1
    eta0 = mapAngle(c1*eta0, [-180, 180], units='degrees')
    if fableFlag:
        eta0  = 90 - eta0

    # must put args into RADIANS
    #   - eta0 is in DEGREES,
    #   - the others are in whatever was entered, hence c2
    eta0  = d2r*eta0
    tht0  = c2*tth0/2
    if chi is not None:
        chi = c2*chi
    else:
        chi = 0

    # ---------------------
    # SYSTEM SOLVE
    #
    #
    # cos(chi)cos(eta)cos(theta)sin(x) - cos(chi)sin(theta)cos(x) = sin(theta) - sin(chi)sin(eta)cos(theta)
    #
    #
    # Identity: a sin x + b cos x = sqrt(a**2 + b**2) sin (x + alfa)
    #
    #       /
    #       |      atan(b/a) for a > 0
    # alfa <
    #       | pi + atan(b/a) for a < 0
    #       \
    #
    # => sin (x + alfa) = c / sqrt(a**2 + b**2)
    #
    # must use both branches for sin(x) = n: x = u (+ 2k*pi) | x = pi - u (+ 2k*pi)
    #
    cchi = num.cos(chi);     schi = num.sin(chi)
    ceta = num.cos(eta0);    seta = num.sin(eta0)
    ctht = num.cos(tht0);    stht = num.sin(tht0)

    nchi = num.c_[0., cchi, schi].T

    gHat0_l = num.vstack([ceta * ctht,
                          seta * ctht,
                          stht])

    a = cchi*ceta*ctht
    b = cchi*schi*seta*ctht + schi*schi*stht - stht
    c = stht + cchi*schi*seta*ctht + schi*schi*stht

    # form solution
    abMag    = num.sqrt(a*a + b*b); assert num.all(abMag > 0), "Beam vector specification is infealible!"
    phaseAng = num.arctan2(b, a)
    rhs      = c / abMag; rhs[abs(rhs) > 1.] = num.nan
    rhsAng   = num.arcsin(rhs)

    # write ome angle output arrays (NaNs persist here)
    ome1 =          rhsAng - phaseAng
    ome2 = num.pi - rhsAng - phaseAng

    ome1 = mapAngle(ome1, [-num.pi, num.pi], units='radians')
    ome2 = mapAngle(ome2, [-num.pi, num.pi], units='radians')

    ome_stack = num.vstack([ome1, ome2])

    min_idx = num.argmin(abs(ome_stack), axis=0)

    ome_min = ome_stack[min_idx, range(len(ome1))]
    eta_min = num.nan * num.ones_like(ome_min)

    # mark feasible reflections
    goodOnes = -num.isnan(ome_min)

    numGood  = sum(goodOnes)
    tmp_eta  = num.empty(numGood)
    tmp_gvec = gHat0_l[:, goodOnes]
    for i in range(numGood):
        come = num.cos(ome_min[goodOnes][i])
        some = num.sin(ome_min[goodOnes][i])
        rchi = rotMatOfExpMap( num.tile(ome_min[goodOnes][i], (3, 1)) * nchi )
        gHat_l = num.dot(rchi, tmp_gvec[:, i].reshape(3, 1))
        tmp_eta[i] = num.arctan2(gHat_l[1], gHat_l[0])
        pass
    eta_min[goodOnes] = tmp_eta

    # everybody back to DEGREES!
    #     - ome1 is in RADIANS here
    #     - convert and put into [-180, 180]
    ome1 = mapAngle( mapAngle(r2d*ome_min, [-180, 180], units='degrees') + c1*ome0, [-180, 180], units='degrees')

    # put eta1 in [-180, 180]
    eta1 = mapAngle(r2d*eta_min, [-180, 180], units='degrees')

    if not outputDegrees:
        ome1 = d2r * ome1
        eta1 = d2r * eta1

    return ome1, eta1
Пример #6
0
    def __call__(self, spotsArray, **kwargs):
        """
        A word on spacegroup numbers: it appears that grainspotter is using the 'VolA' tag for calls to SgInfo
        """
        location = self.__class__.__name__
        tic = time.time()

        # keyword argument processing
        phaseID     = None
        gVecFName   = 'tmpGve'
        sgNum       = 225
        cellString  = 'F'
        omeRange    = num.r_[-60, 60]   # in DEGREES
        deltaOme    = 0.25              # in DEGREES
        minMeas     = 24
        minCompl    = 0.7
        minUniqn    = 0.5
        uncertainty = [0.10, 0.25, .50] # in DEGREES
        eulStep     = 2                 # in DEGREES
        nSigmas     = 2
        minFracG    = 0.90
        numTrials   = 100000
        positionFit = False

        kwarglen = len(kwargs)
        if kwarglen > 0:
            argkeys = kwargs.keys()
            for i in range(kwarglen):
                if argkeys[i] == 'sgNum':
                    sgNum = kwargs[argkeys[i]]
                elif argkeys[i] == 'phaseID':
                    phaseID = kwargs[argkeys[i]]
                elif argkeys[i] == 'gVecFName':
                    gVecFName = kwargs[argkeys[i]]
                elif argkeys[i] == 'cellString':
                    cellString = kwargs[argkeys[i]]
                elif argkeys[i] == 'omeRange':
                    omeRange = kwargs[argkeys[i]]
                elif argkeys[i] == 'deltaOme':
                    deltaOme = kwargs[argkeys[i]]
                elif argkeys[i] == 'minMeas':
                    minMeas = kwargs[argkeys[i]]
                elif argkeys[i] == 'minCompl':
                    minCompl = kwargs[argkeys[i]]
                elif argkeys[i] == 'minUniqn':
                    minUniqn = kwargs[argkeys[i]]
                elif argkeys[i] == 'uncertainty':
                    uncertainty = kwargs[argkeys[i]]
                elif argkeys[i] == 'eulStep':
                    eulStep = kwargs[argkeys[i]]
                elif argkeys[i] == 'nSigmas':
                    nSigmas = kwargs[argkeys[i]]
                elif argkeys[i] == 'minFracG':
                    minFracG = kwargs[argkeys[i]]
                elif argkeys[i] == 'nTrials':
                    numTrials = kwargs[argkeys[i]]
                elif argkeys[i] == 'positionfit':
                    positionFit = kwargs[argkeys[i]]
                else:
                    raise RuntimeError, "Unrecognized keyword argument '%s'" % (argkeys[i])

        # cleanup stuff from any previous run
        self.cleanup()

        planeData = spotsArray.getPlaneData(phaseID=phaseID)
        cellp   = planeData.latVecOps['dparms']
        U0      = planeData.latVecOps['U0']
        wlen    = planeData.wavelength
        dsp     = planeData.getPlaneSpacings()
        fHKLs   = planeData.getSymHKLs()
        tThRng  = planeData.getTThRanges()
        symTag  = planeData.getLaueGroup()

        tThMin, tThMax = (r2d*tThRng.min(), r2d*tThRng.max()) # single range should be ok since entering hkls
        etaMin, etaMax = (0, 360)   # not sure when this will ever *NOT* be the case, so setting it

        omeMin = spotsArray.getOmegaMins()
        omeMax = spotsArray.getOmegaMaxs()
        omeRangeString = ''
        for iOme in range(len(omeMin)):
            omeRangeString += 'omegarange %g %g\n' % (omeMin[iOme] * r2d, omeMax[iOme] * r2d)

        # convert angles
        cellp[3:] = r2d*cellp[3:]

        # make the theoretical hkls string
        gvecHKLString = ''
        for i in range(len(dsp)):
            for j in range(fHKLs[i].shape[1]):
                gvecHKLString += '%1.8f %d %d %d\n' % (1/dsp[i], fHKLs[i][0, j], fHKLs[i][1, j], fHKLs[i][2, j])

        # now for the measured data section
        # xr yr zr xc yc ds eta omega
        gvecString = ''
        ii = 0
        spotsIter = spotsArray.getIterPhase(phaseID, returnBothCoordTypes=True)
        for iSpot, angCOM, xyoCOM in spotsIter:
            sX, sY, sOme     = xyoCOM                          # detector coords
            sTTh, sEta, sOme = angCOM                          # angular coords (radians)
            sDsp = wlen / 2. / num.sin(0.5*sTTh)               # dspacing

            # convert eta to risoe frame
            rEta = mapAngle(90. - r2d*sEta, [0, 360], units='degrees')

            # make mesaured G vector components in risoe frame
            mGvec = makeMeasuredScatteringVectors(sTTh, sEta, sOme, convention='risoe', frame='sample')
            # mQvec = makeMeasuredScatteringVectors(sTTh, sEta, sOme, convention='llnl', frame='lab')
            gveXYZ = spotsArray.detectorGeom.angToXYO(sTTh, sEta, sOme, outputGve=True)

            mGvec = mGvec / sDsp
            # mQvec = 4*num.pi*num.sin(0.5*sTTh)*mQvec/wlen

            # make contribution
            gvecString += '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %1.8f %d %1.8f %1.8f %1.8f\n' \
                          % (mGvec[0], mGvec[1], mGvec[2], \
                             sX, sY, \
                             1/sDsp, rEta, r2d*sOme, \
                             iSpot, \
                             gveXYZ[0, :], gveXYZ[1, :], gveXYZ[2, :])

            # advance counter
            ii += 1

        # write gve file for grainspotter
        f = open(gVecFName+'.gve', 'w')
        print >> f, '%1.8f %1.8f %1.8f %1.8f %1.8f %1.8f ' % tuple(cellp) + \
              cellString + '\n' + \
              '# wavelength = %1.8f\n' % (wlen) + \
              '# wedge = 0.000000\n# ds h k l\n' + \
              gvecHKLString + \
              '# xr yr zr xc yc ds eta omega\n' + \
              gvecString
        f.close()

        ###############################################################
        # GrainSpotter ini parameters
        #
        # tempFNameIn = tempfile.mktemp()
        if positionFit:
            positionString = 'positionfit'
        else:
            positionString = '!positionfit'

        if numTrials == 0:
            randomString = '!random\n'
        else:
            randomString = 'random %g\n' % (numTrials)

        tempFNameIn = 'tmpIni'
        f = open(tempFNameIn, 'w')
        # self.__tempFNameList.append(tempFNameIn)
        print >> f, \
              'spacegroup %d\n' % (sgNum) + \
              'tthrange %g %g\n' % (tThMin, tThMax) + \
              'etarange %g %g\n' % (etaMin, etaMax) + \
              'domega %g\n' % (deltaOme) + \
              omeRangeString + \
              'filespecs %s.gve %s.log\n' % (gVecFName, tempFNameIn) + \
              'cuts %d %g %g\n' % (minMeas, minCompl, minUniqn) + \
              'eulerstep %g\n' % (eulStep)+ \
              'uncertainties %g %g %g\n' % (uncertainty[0], uncertainty[1], uncertainty[2]) + \
              'nsigmas %d\n' % (nSigmas) + \
              'minfracg %g\n' % (minFracG) + \
              randomString + \
              positionString + '\n'
        f.close()

        toc = time.time()
        print 'in %s, setup took %g' % (location, toc-tic)
        tic = time.time()

        # tempFNameStdout = tempfile.mktemp()
        # self.__tempFNameList.append(tempFNameStdout)
        tempFNameStdout = 'tmp.out'
        # grainSpotterCmd = '%s %s > %s' % (self.__execName, tempFNameIn, tempFNameStdout)
        grainSpotterCmd = '%s %s' % (self.__execName, tempFNameIn)
        os.system(grainSpotterCmd)
        toc = time.time()
        print 'in %s, execution took %g' % (location, toc-tic)
        tic = time.time()

        # add output files to cleanup list
        # self.__tempFNameList += glob.glob(tempFNameIn+'.*')

        # collect data from gff file'
        gffFile = tempFNameIn+'.gff'
        gffData = num.loadtxt(gffFile)
        if gffData.ndim == 1:
            gffData = gffData.reshape(1, len(gffData))
        gffData_U = gffData[:,6:6+9]

        # process for output
        retval = convertUToRotMat(gffData_U, U0, symTag=symTag)

        toc = time.time()
        print 'in %s, post-processing took %g' % (location, toc-tic)
        tic = time.time()

        return retval