Esempio n. 1
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Return dictionary of all virtual angles in radians from VliegPosition
        object win radians and wavelength in Angstroms. The virtual angles are:
        Bin, Bout, azimuth and 2theta.
        """

        # Create transformation matrices
        [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
            pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD, self._getTau() * TORAD)

        S = TAU * SIGMA
        y_vector = matrix([[0], [1], [0]])

        # Calculate Bin from equation 15:
        surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
        incoming_alpha = ALPHA.I * y_vector
        minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
        Bin = asin(bound(-minusSinBetaIn))

        # Calculate Bout from equation 16:
        #  surfacenormal_alpha has just ben calculated
        outgoing_alpha = DELTA * GAMMA * y_vector
        sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
        Bout = asin(bound(sinBetaOut))

        # Calculate 2theta from equation 25:

        cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
        twotheta = acos(bound(cosTwoTheta))
        psi = self._anglesToPsi(pos, wavelength)

        return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
Esempio n. 2
0
    def _calc_remaining_reference_angles(self, name, value, theta, tau):
        """Return psi, alpha and beta given one of a_eq_b, alpha, beta or psi
        """
        if sin(tau) == 0:
            raise DiffcalcException(
                'The scattering vector (Q) and the reference vector (n) are\n'
                'parallel. The constraint %s could not be used to determine a\n'
                'unique azimuthal rotation about the Q vector.' % name)
        if cos(theta) == 0:
            raise DiffcalcException(
                'The constraint %s could not be used to determine a unique '
                'azimuth (psi) as the scattering vector (Q) and xray beam are '
                "are parallel and don't form a unique'reference plane" % name)

        if name == 'psi':
            psi = value
            # Equation 26 for alpha
            sin_alpha = (cos(tau) * sin(theta) -
                         cos(theta) * sin(tau) * cos(psi))
            if abs(sin_alpha) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))
            alpha = asin(bound(sin_alpha))
            # Equation 27 for beta
            sin_beta = cos(tau) * sin(theta) + cos(theta) * sin(tau) * cos(psi)
            if abs(sin_beta) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))

            beta = asin(bound(sin_beta))

        elif name == 'a_eq_b':
            alpha = beta = asin(bound(cos(tau) * sin(theta)))            # (24)

        elif name == 'alpha':
            alpha = value                                                # (24)
            sin_beta = 2 * sin(theta) * cos(tau) - sin(alpha)
            if abs(sin_beta) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))
            beta = asin(sin_beta)

        elif name == 'beta':
            beta = value
            sin_alpha = 2 * sin(theta) * cos(tau) - sin(beta)            # (24)
            if abs(sin_alpha) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))

            alpha = asin(sin_alpha)

        if name != 'psi':
            cos_psi = ((cos(tau) * sin(theta) - sin(alpha)) /            # (28)
                       (sin(tau) * cos(theta)))
            if abs(cos_psi) > (1 + SMALL):
                hint = "\nAlpha may be too low?" if name == 'alpha' else "";
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG) + hint)
            # TODO: If set, alpha is probably too low

            psi = acos(bound(cos_psi))
        return psi, alpha, beta
Esempio n. 3
0
    def _calc_remaining_reference_angles(self, name, value, theta, tau):
        """Return psi, alpha and beta given one of a_eq_b, alpha, beta or psi
        """
        if sin(tau) == 0:
            raise DiffcalcException(
                'The scattering vector (Q) and the reference vector (n) are\n'
                'parallel. The constraint %s could not be used to determine a\n'
                'unique azimuthal rotation about the Q vector.' % name)
        if cos(theta) == 0:
            raise DiffcalcException(
                'The constraint %s could not be used to determine a unique '
                'azimuth (psi) as the scattering vector (Q) and xray beam are '
                "are parallel and don't form a unique'reference plane" % name)

        if name == 'psi':
            psi = value
            # Equation 26 for alpha
            sin_alpha = (cos(tau) * sin(theta) -
                         cos(theta) * sin(tau) * cos(psi))
            if abs(sin_alpha) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))
            alpha = asin(bound(sin_alpha))
            # Equation 27 for beta
            sin_beta = cos(tau) * sin(theta) + cos(theta) * sin(tau) * cos(psi)
            if abs(sin_beta) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))

            beta = asin(bound(sin_beta))

        elif name == 'a_eq_b':
            alpha = beta = asin(bound(cos(tau) * sin(theta)))            # (24)

        elif name == 'alpha':
            alpha = value                                                # (24)
            sin_beta = 2 * sin(theta) * cos(tau) - sin(alpha)
            if abs(sin_beta) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))
            beta = asin(sin_beta)

        elif name == 'beta':
            beta = value
            sin_alpha = 2 * sin(theta) * cos(tau) - sin(beta)            # (24)
            if abs(sin_alpha) > 1 + SMALL:
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG))

            alpha = asin(sin_alpha)

        if name != 'psi':
            cos_psi = ((cos(tau) * sin(theta) - sin(alpha)) /            # (28)
                       (sin(tau) * cos(theta)))
            if abs(cos_psi) > (1 + SMALL):
                hint = "\nAlpha may be too low?" if name == 'alpha' else "";
                raise DiffcalcException(UNREACHABLE_MSG % (name, value * TODEG) + hint)
            # TODO: If set, alpha is probably too low

            psi = acos(bound(cos_psi))
        return psi, alpha, beta
Esempio n. 4
0
    def _calc_remaining_detector_angles(self, constraint_name,
                                        constraint_value, theta):
        """Return delta, nu and qaz given one detector angle
        """
        #                                                         (section 5.1)
        # Find qaz using various derivations of 17 and 18
        if constraint_name == 'delta':
            delta = constraint_value
            sin_2theta = sin(2 * theta)
            if is_small(sin_2theta):
                raise DiffcalcException(
                    'No meaningful scattering vector (Q) can be found when '
                    'theta is so small (%.4f).' % theta * TODEG)
            qaz = asin(bound(sin(delta) / sin_2theta))              # (17 & 18)

        elif constraint_name == NUNAME:
            nu = constraint_value
#            cos_delta = cos(2*theta) / cos(nu)#<--fails when nu = 90
#            delta = acos(bound(cos_delta))
#            tan
            sin_2theta = sin(2 * theta)
            if is_small(sin_2theta):
                raise DiffcalcException(
                    'No meaningful scattering vector (Q) can be found when '
                    'theta is so small (%.4f).' % theta * TODEG)
            cos_qaz = tan(nu) / tan(2 * theta)
            if abs(cos_qaz) > 1 + SMALL:
                raise DiffcalcException(
                    'The specified %s=%.4f is greater than the 2theta (%.4f)'
                    % (NUNAME, nu, theta))
            qaz = acos(bound(cos_qaz))

        elif constraint_name == 'qaz':
            qaz = constraint_value

        else:
            raise ValueError(
                constraint_name + ' is not an explicit detector angle '
                '(naz cannot be handled here)')

        if constraint_name != NUNAME:
            nu = atan2(sin(2 * theta) * cos(qaz), cos(2 * theta))

        if constraint_name != 'delta':
            cos_qaz = cos(qaz)
            if not is_small(cos_qaz):  # TODO: switch methods at 45 deg?
                delta = atan2(sin(qaz) * sin(nu), cos_qaz)
            else:
                # qaz is close to 90 (a common place for it)
                delta = sign(qaz) * acos(bound(cos(2 * theta) / cos(nu)))

        return delta, nu, qaz
Esempio n. 5
0
    def _calc_remaining_detector_angles(self, constraint_name,
                                        constraint_value, theta):
        """Return delta, nu and qaz given one detector angle
        """
        #                                                         (section 5.1)
        # Find qaz using various derivations of 17 and 18
        if constraint_name == 'delta':
            delta = constraint_value
            sin_2theta = sin(2 * theta)
            if is_small(sin_2theta):
                raise DiffcalcException(
                    'No meaningful scattering vector (Q) can be found when '
                    'theta is so small (%.4f).' % theta * TODEG)
            qaz = asin(bound(sin(delta) / sin_2theta))              # (17 & 18)

        elif constraint_name == NUNAME:
            nu = constraint_value
#            cos_delta = cos(2*theta) / cos(nu)#<--fails when nu = 90
#            delta = acos(bound(cos_delta))
#            tan
            sin_2theta = sin(2 * theta)
            if is_small(sin_2theta):
                raise DiffcalcException(
                    'No meaningful scattering vector (Q) can be found when '
                    'theta is so small (%.4f).' % theta * TODEG)
            cos_qaz = tan(nu) / tan(2 * theta)
            if abs(cos_qaz) > 1 + SMALL:
                raise DiffcalcException(
                    'The specified %s=%.4f is greater than the 2theta (%.4f)'
                    % (NUNAME, nu, theta))
            qaz = acos(bound(cos_qaz))

        elif constraint_name == 'qaz':
            qaz = constraint_value

        else:
            raise ValueError(
                constraint_name + ' is not an explicit detector angle '
                '(naz cannot be handled here)')

        if constraint_name != NUNAME:
            nu = atan2(sin(2 * theta) * cos(qaz), cos(2 * theta))

        if constraint_name != 'delta':
            cos_qaz = cos(qaz)
            if not is_small(cos_qaz):  # TODO: switch methods at 45 deg?
                delta = atan2(sin(qaz) * sin(nu), cos_qaz)
            else:
                # qaz is close to 90 (a common place for it)
                delta = sign(qaz) * acos(bound(cos(2 * theta) / cos(nu)))

        return delta, nu, qaz
Esempio n. 6
0
    def _anglesToVirtualAngles(self, pos, _wavelength):
        """Calculate pseudo-angles in radians from position in radians.

        Return theta, qaz, alpha, naz, tau, psi and beta in a dictionary.

        """

        # depends on surface normal n_lab.
        mu, delta, nu, eta, chi, phi = pos.totuple()

        theta, qaz = _theta_and_qaz_from_detector_angles(delta, nu)      # (19)

        [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu,
                                           delta, nu, eta, chi, phi)
        Z = MU * ETA * CHI * PHI
        n_lab = Z * self._get_n_phi()
        alpha = asin(bound((-n_lab[1, 0])))
        naz = atan2(n_lab[0, 0], n_lab[2, 0])                            # (20)

        cos_tau = cos(alpha) * cos(theta) * cos(naz - qaz) + \
                  sin(alpha) * sin(theta)
        tau = acos(bound(cos_tau))                                       # (23)

        # Compute Tau using the dot product directly (THIS ALSO WORKS)
#        q_lab = ( (NU * DELTA - I ) * matrix([[0],[1],[0]])
#        norm = norm(q_lab)
#        q_lab = matrix([[1],[0],[0]]) if norm == 0 else q_lab * (1/norm)
#        tau_from_dot_product = acos(bound(dot3(q_lab, n_lab)))

        sin_beta = 2 * sin(theta) * cos(tau) - sin(alpha)
        beta = asin(bound(sin_beta))                                     # (24)

        sin_tau = sin(tau)
        cos_theta = cos(theta)
        if sin_tau == 0:
            psi = float('Nan')
            print ('WARNING: Diffcalc could not calculate a unique azimuth '
                   '(psi) as the scattering vector (Q) and the reference '
                   'vector (n) are parallel')
        elif cos_theta == 0:
            psi = float('Nan')
            print ('WARNING: Diffcalc could not calculate a unique azimuth '
                   '(psi) because the scattering vector (Q) and xray beam are '
                   " are parallel and don't form a unique reference plane")
        else:
            cos_psi = ((cos(tau) * sin(theta) - sin(alpha)) /
                       (sin_tau * cos_theta))
            psi = acos(bound(cos_psi))                                   # (28)

        return {'theta': theta, 'qaz': qaz, 'alpha': alpha,
                'naz': naz, 'tau': tau, 'psi': psi, 'beta': beta}
Esempio n. 7
0
    def _anglesToVirtualAngles(self, pos, _wavelength):
        """Calculate pseudo-angles in radians from position in radians.

        Return theta, qaz, alpha, naz, tau, psi and beta in a dictionary.

        """

        # depends on surface normal n_lab.
        mu, delta, nu, eta, chi, phi = pos.totuple()

        theta, qaz = _theta_and_qaz_from_detector_angles(delta, nu)      # (19)

        [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu,
                                           delta, nu, eta, chi, phi)
        Z = MU * ETA * CHI * PHI
        n_lab = Z * self._get_n_phi()
        alpha = asin(bound((-n_lab[1, 0])))
        naz = atan2(n_lab[0, 0], n_lab[2, 0])                            # (20)

        cos_tau = cos(alpha) * cos(theta) * cos(naz - qaz) + \
                  sin(alpha) * sin(theta)
        tau = acos(bound(cos_tau))                                       # (23)

        # Compute Tau using the dot product directly (THIS ALSO WORKS)
#        q_lab = ( (NU * DELTA - I ) * matrix([[0],[1],[0]])
#        norm = norm(q_lab)
#        q_lab = matrix([[1],[0],[0]]) if norm == 0 else q_lab * (1/norm)
#        tau_from_dot_product = acos(bound(dot3(q_lab, n_lab)))

        sin_beta = 2 * sin(theta) * cos(tau) - sin(alpha)
        beta = asin(bound(sin_beta))                                     # (24)

        sin_tau = sin(tau)
        cos_theta = cos(theta)
        if sin_tau == 0:
            psi = float('Nan')
            print ('WARNING: Diffcalc could not calculate a unique azimuth '
                   '(psi) as the scattering vector (Q) and the reference '
                   'vector (n) are parallel')
        elif cos_theta == 0:
            psi = float('Nan')
            print ('WARNING: Diffcalc could not calculate a unique azimuth '
                   '(psi) because the scattering vector (Q) and xray beam are '
                   " are parallel and don't form a unique reference plane")
        else:
            cos_psi = ((cos(tau) * sin(theta) - sin(alpha)) /
                       (sin_tau * cos_theta))
            psi = acos(bound(cos_psi))                                   # (28)

        return {'theta': theta, 'qaz': qaz, 'alpha': alpha,
                'naz': naz, 'tau': tau, 'psi': psi, 'beta': beta}
Esempio n. 8
0
        def equation49through59(psi):
            # equation 49 R = (D^-1)*PI*D*Ro
            PSI = createVliegsPsiTransformationMatrix(psi)
            R = D.I * PSI * D * Ro

            #  eq 57: extract omega from R
            if abs(R[0, 2]) < 1e-20:
                omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
            else:
                omega = -atan2(R[1, 2], R[0, 2])

            # eq 58: extract chi from R
            sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
            sinchi = bound(sinchi)
            check(abs(sinchi) <= 1, 'could not compute chi')
            # (there are two roots to this equation, but only the first is also
            # a solution to R33=cos(chi))
            chi = asin(sinchi)

            # eq 59: extract phi from R
            if abs(R[2, 0]) < 1e-20:
                phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
            else:
                phi = atan2(-R[2, 1], -R[2, 0])
            return omega, chi, phi
Esempio n. 9
0
        def equation49through59(psi):
            # equation 49 R = (D^-1)*PI*D*Ro
            PSI = createVliegsPsiTransformationMatrix(psi)
            R = D.I * PSI * D * Ro

            #  eq 57: extract omega from R
            if abs(R[0, 2]) < 1e-20:
                omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
            else:
                omega = -atan2(R[1, 2], R[0, 2])

            # eq 58: extract chi from R
            sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
            sinchi = bound(sinchi)
            check(abs(sinchi) <= 1, 'could not compute chi')
            # (there are two roots to this equation, but only the first is also
            # a solution to R33=cos(chi))
            chi = asin(sinchi)

            # eq 59: extract phi from R
            if abs(R[2, 0]) < 1e-20:
                phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
            else:
                phi = atan2(-R[2, 1], -R[2, 0])
            return omega, chi, phi
Esempio n. 10
0
    def asynchronousMoveTo(self, newpos):

        pos = self.diffhw.getPosition()  # a tuple
        (hkl_pos , _) = self._diffcalc.angles_to_hkl(pos)

        nref_hkl = [i[0] for i in self._diffcalc._ub.ubcalc.n_hkl.tolist()]
        pol, az_nref, sc = self._diffcalc._ub.ubcalc.calc_offset_for_hkl(hkl_pos, nref_hkl)
        if pol < SMALL:
            az_nref = 0
        sc_nref_hkl = [sc * v for v in nref_hkl]

        _ubm = self._diffcalc._ub.ubcalc._get_UB()
        qvec = _ubm * matrix(hkl_pos).T
        qvec_rlu = sqrt(dot3(qvec, qvec)) * self._diffcalc._ub.ubcalc.get_hkl_plane_distance(nref_hkl) / (2.*pi)

        try:
            newpol = acos(bound(newpos / qvec_rlu))
        except AssertionError:
            raise DiffcalcException("Scattering vector projection value of %.5f r.l.u. unreachable." % newpos)

        try:
            hkl_offset = self._diffcalc._ub.ubcalc.calc_hkl_offset(*sc_nref_hkl, pol=newpol, az=az_nref)
            (pos, _) = self._diffcalc.hkl_to_angles(*hkl_offset)
        except DiffcalcException as e:
            if DEBUG:
                raise
            else:
                raise DiffcalcException(e.message)

        self.diffhw.asynchronousMoveTo(pos)
Esempio n. 11
0
def gammaOnArmToBase(deltaA, gammaA, alpha):
    """
    (deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in
    radians)

    Maps delta and gamma for an instrument where the gamma circle is on
    the delta arm to the case where it rests on the base.

    There are always two possible solutions. To get the second apply the
    transform:

        delta --> 180-delta (reflect and flip to opposite side)
        gamma --> 180+gamma (flip to opposite side)

    This code will return the solution where gamma is positive, but will
    warn if a sign change was made.
    """

    ### Equation 9 ###
    deltaB1 = asin(bound(sin(deltaA) * cos(gammaA)))
    # ...second root:
    if deltaB1 >= 0:
        deltaB2 = pi - deltaB1
    else:
        deltaB2 = -pi - deltaB1

    ### Equation 10 ###:
    if fabs(cos(deltaA)) < 1e-20:
        gammaB1 = sign(tan(gammaA)) * sign(cos(deltaA)) * pi / 2 + alpha
    else:
        gammaB1 = atan(tan(gammaA) / cos(deltaA)) + alpha
    #... second root:
    if gammaB1 <= 0:
        gammaB2 = gammaB1 + pi
    else:
        gammaB2 = gammaB1 - pi

    ### Choose the solution that fits equation 8 ###
    if (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB1)
            and 0 <= gammaB1 <= pi):
        deltaB, gammaB = deltaB1, gammaB1
    elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB1)
          and 0 <= gammaB1 <= pi):
        deltaB, gammaB = deltaB2, gammaB1
        print "gammaOnArmToBase choosing 2nd delta root (to physical)"
    elif (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB2)
          and 0 <= gammaB2 <= pi):
        print "gammaOnArmToBase choosing 2nd gamma root (to physical)"
        deltaB, gammaB = deltaB1, gammaB2
    elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB2)
          and 0 <= gammaB2 <= pi):
        print "gammaOnArmToBase choosing 2nd delta root and 2nd gamma root"
        deltaB, gammaB = deltaB2, gammaB2
    else:
        raise RuntimeError(
            "No valid solutions found mapping gamma-on-arm to gamma-on-base")

    return deltaB, gammaB
Esempio n. 12
0
    def _determineDelta(self, hklPhiNorm, alpha, gamma):
        """
        (delta, twotheta) = _determineDelta(hklPhiNorm, alpha, gamma) --
        computes delta for all modes. Also returns twotheta for sanity
        checking. hklPhiNorm is a 3X1 matrix.

        alpha, gamma & delta - in radians.
        h k & l normalised to wavevector and in phi axis coordinates
        """
        h = hklPhiNorm[0, 0]
        k = hklPhiNorm[1, 0]
        l = hklPhiNorm[2, 0]
        # See Vlieg section 5 (with K=1)
        cosdelta = ((1 + sin(gamma) * sin(alpha) -
                     (h * h + k * k + l * l) / 2) / (cos(gamma) * cos(alpha)))
        costwotheta = (cos(alpha) * cos(gamma) * bound(cosdelta) -
                       sin(alpha) * sin(gamma))
        return (acos(bound(cosdelta)), acos(bound(costwotheta)))
Esempio n. 13
0
    def _determineDelta(self, hklPhiNorm, alpha, gamma):
        """
        (delta, twotheta) = _determineDelta(hklPhiNorm, alpha, gamma) --
        computes delta for all modes. Also returns twotheta for sanity
        checking. hklPhiNorm is a 3X1 matrix.

        alpha, gamma & delta - in radians.
        h k & l normalised to wavevector and in phi axis coordinates
        """
        h = hklPhiNorm[0, 0]
        k = hklPhiNorm[1, 0]
        l = hklPhiNorm[2, 0]
        # See Vlieg section 5 (with K=1)
        cosdelta = ((1 + sin(gamma) * sin(alpha) - (h * h + k * k + l * l) / 2)
                    / (cos(gamma) * cos(alpha)))
        costwotheta = (cos(alpha) * cos(gamma) * bound(cosdelta) -
                       sin(alpha) * sin(gamma))
        return (acos(bound(cosdelta)), acos(bound(costwotheta)))
Esempio n. 14
0
def _theta_and_qaz_from_detector_angles(delta, nu):
    # Equation 19:
    cos_2theta = cos(delta) * cos(nu)
    theta = acos(bound(cos_2theta)) / 2.
    qaz = atan2(tan(delta), sin(nu))
    # qaz flips downward if delta > 90, so flip it back (kludge)
    if delta > pi / 2:
        qaz *= -1
    return theta, qaz
Esempio n. 15
0
def _calc_angle_between_naz_and_qaz(theta, alpha, tau):
    # Equation 30:
    top = cos(tau) - sin(alpha) * sin(theta)
    bottom = cos(alpha) * cos(theta)
    if is_small(bottom):
        if is_small(cos(alpha)):
            raise ValueError('cos(alpha) is too small')
        if is_small(cos(theta)):
            raise ValueError('cos(theta) is too small')
    return acos(bound(top / bottom))
Esempio n. 16
0
def _calc_angle_between_naz_and_qaz(theta, alpha, tau):
    # Equation 30:
    top = cos(tau) - sin(alpha) * sin(theta)
    bottom = cos(alpha) * cos(theta)
    if is_small(bottom):
        if is_small(cos(alpha)):
            raise ValueError('cos(alpha) is too small')
        if is_small(cos(theta)):
            raise ValueError('cos(theta) is too small')
    return acos(bound(top / bottom))
Esempio n. 17
0
def gammaOnBaseToArm(deltaB, gammaB, alpha):
    """
    (deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in
    radians)

    Maps delta and gamma for an instrument where the gamma circle rests on
    the base to the case where it is on the delta arm.

    There are always two possible solutions. To get the second apply the
    transform:

        delta --> 180+delta (flip to opposite side of circle)
        gamma --> 180+gamma (flip to opposite side of circle)

    This code will return the solution where gamma is between 0 and 180.
    """

    ### Equation11 ###
    if fabs(cos(gammaB - alpha)) < 1e-20:
        deltaA1 = sign(tan(deltaB)) * sign(cos(gammaB - alpha)) * pi / 2
    else:
        deltaA1 = atan(tan(deltaB) / cos(gammaB - alpha))
    # ...second root
    if deltaA1 <= 0:
        deltaA2 = deltaA1 + pi
    else:
        deltaA2 = deltaA1 - pi

    ### Equation 12 ###
    gammaA1 = asin(bound(cos(deltaB) * sin(gammaB - alpha)))
    # ...second root
    if gammaA1 >= 0:
        gammaA2 = pi - gammaA1
    else:
        gammaA2 = -pi - gammaA1

    # Choose the delta solution that fits equations 8
    if solvesEq8(alpha, deltaA1, gammaA1, deltaB, gammaB):
        deltaA, gammaA = deltaA1, gammaA1
    elif solvesEq8(alpha, deltaA2, gammaA1, deltaB, gammaB):
        deltaA, gammaA = deltaA2, gammaA1
        print "gammaOnBaseToArm choosing 2nd delta root (to internal)"
    elif solvesEq8(alpha, deltaA1, gammaA2, deltaB, gammaB):
        print "gammaOnBaseToArm choosing 2nd gamma root (to internal)"
        deltaA, gammaA = deltaA1, gammaA2
    elif solvesEq8(alpha, deltaA2, gammaA2, deltaB, gammaB):
        print "gammaOnBaseToArm choosing 2nd delta root and 2nd gamma root"
        deltaA, gammaA = deltaA2, gammaA2
    else:
        raise RuntimeError(
            "No valid solutions found mapping from gamma-on-base to gamma-on-arm"
        )

    return deltaA, gammaA
Esempio n. 18
0
 def get_miscut_angle_axis(self, ubmatrix):
     y = self._get_surf_nphi()
     l = ubmatrix * y
     rotation_axis = self._tobj.transform(cross3(y, l), True)
     if abs(norm(rotation_axis)) < SMALL:
         rotation_axis = matrix('0; 0; 0')
         rotation_angle = 0
     else:
         rotation_axis = rotation_axis * (1 / norm(rotation_axis))
         cos_rotation_angle = bound(dot3(y, l) / norm(l))
         rotation_angle = acos(cos_rotation_angle) * TODEG
     return rotation_angle, rotation_axis
Esempio n. 19
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Calculate virtual-angles in radians from position in radians.

        Return theta, alpha, and beta in a dictionary.
        """

        betain = pos.omegah                                              # (52)

        hkl = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
                              wavelength, self._UB)
        H_phi = self._UB * hkl
        H_phi = H_phi / (2 * pi / wavelength)
        l_phi = H_phi[2, 0]
        sin_betaout = l_phi - sin(betain)
        betaout = asin(bound(sin_betaout))                               # (54)

        cos_2theta = cos(pos.delta) * cos(pos.gamma)
        theta = acos(bound(cos_2theta)) / 2.

        return {'theta': theta, 'betain': betain, 'betaout': betaout}
Esempio n. 20
0
def gammaOnArmToBase(deltaA, gammaA, alpha):
    """
    (deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in
    radians)

    Maps delta and gamma for an instrument where the gamma circle is on
    the delta arm to the case where it rests on the base.

    There are always two possible solutions. To get the second apply the
    transform:

        delta --> 180-delta (reflect and flip to opposite side)
        gamma --> 180+gamma (flip to opposite side)

    This code will return the solution where gamma is positive, but will
    warn if a sign change was made.
    """

    ### Equation 9 ###
    deltaB1 = asin(bound(sin(deltaA) * cos(gammaA)))
    # ...second root:
    if deltaB1 >= 0:
        deltaB2 = pi - deltaB1
    else:
        deltaB2 = -pi - deltaB1

    ### Equation 10 ###:
    if fabs(cos(deltaA)) < 1e-20:
        gammaB1 = sign(tan(gammaA)) * sign(cos(deltaA)) * pi / 2 + alpha
    else:
        gammaB1 = atan(tan(gammaA) / cos(deltaA)) + alpha
    # ... second root:
    if gammaB1 <= 0:
        gammaB2 = gammaB1 + pi
    else:
        gammaB2 = gammaB1 - pi

    ### Choose the solution that fits equation 8 ###
    if solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB1) and 0 <= gammaB1 <= pi:
        deltaB, gammaB = deltaB1, gammaB1
    elif solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB1) and 0 <= gammaB1 <= pi:
        deltaB, gammaB = deltaB2, gammaB1
        print "gammaOnArmToBase choosing 2nd delta root (to physical)"
    elif solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB2) and 0 <= gammaB2 <= pi:
        print "gammaOnArmToBase choosing 2nd gamma root (to physical)"
        deltaB, gammaB = deltaB1, gammaB2
    elif solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB2) and 0 <= gammaB2 <= pi:
        print "gammaOnArmToBase choosing 2nd delta root and 2nd gamma root"
        deltaB, gammaB = deltaB2, gammaB2
    else:
        raise RuntimeError("No valid solutions found mapping gamma-on-arm to gamma-on-base")

    return deltaB, gammaB
Esempio n. 21
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Calculate virtual-angles in radians from position in radians.

        Return theta, alpha, and beta in a dictionary.
        """

        betain = pos.omegah  # (52)

        hkl = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
                            wavelength, self._UB)
        H_phi = self._UB * hkl
        H_phi = H_phi / (2 * pi / wavelength)
        l_phi = H_phi[2, 0]
        sin_betaout = l_phi - sin(betain)
        betaout = asin(bound(sin_betaout))  # (54)

        cos_2theta = cos(pos.delta) * cos(pos.gamma)
        theta = acos(bound(cos_2theta)) / 2.

        return {'theta': theta, 'betain': betain, 'betaout': betaout}
Esempio n. 22
0
def gammaOnBaseToArm(deltaB, gammaB, alpha):
    """
    (deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in
    radians)

    Maps delta and gamma for an instrument where the gamma circle rests on
    the base to the case where it is on the delta arm.

    There are always two possible solutions. To get the second apply the
    transform:

        delta --> 180+delta (flip to opposite side of circle)
        gamma --> 180+gamma (flip to opposite side of circle)

    This code will return the solution where gamma is between 0 and 180.
    """

    ### Equation11 ###
    if fabs(cos(gammaB - alpha)) < 1e-20:
        deltaA1 = sign(tan(deltaB)) * sign(cos(gammaB - alpha)) * pi / 2
    else:
        deltaA1 = atan(tan(deltaB) / cos(gammaB - alpha))
    # ...second root
    if deltaA1 <= 0:
        deltaA2 = deltaA1 + pi
    else:
        deltaA2 = deltaA1 - pi

    ### Equation 12 ###
    gammaA1 = asin(bound(cos(deltaB) * sin(gammaB - alpha)))
    # ...second root
    if gammaA1 >= 0:
        gammaA2 = pi - gammaA1
    else:
        gammaA2 = -pi - gammaA1

    # Choose the delta solution that fits equations 8
    if solvesEq8(alpha, deltaA1, gammaA1, deltaB, gammaB):
        deltaA, gammaA = deltaA1, gammaA1
    elif solvesEq8(alpha, deltaA2, gammaA1, deltaB, gammaB):
        deltaA, gammaA = deltaA2, gammaA1
        print "gammaOnBaseToArm choosing 2nd delta root (to internal)"
    elif solvesEq8(alpha, deltaA1, gammaA2, deltaB, gammaB):
        print "gammaOnBaseToArm choosing 2nd gamma root (to internal)"
        deltaA, gammaA = deltaA1, gammaA2
    elif solvesEq8(alpha, deltaA2, gammaA2, deltaB, gammaB):
        print "gammaOnBaseToArm choosing 2nd delta root and 2nd gamma root"
        deltaA, gammaA = deltaA2, gammaA2
    else:
        raise RuntimeError("No valid solutions found mapping from gamma-on-base to gamma-on-arm")

    return deltaA, gammaA
Esempio n. 23
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Return dictionary of all virtual angles in radians from VliegPosition
        object win radians and wavelength in Angstroms. The virtual angles are:
        Bin, Bout, azimuth and 2theta.
        """

        # Create transformation matrices
        [ALPHA, DELTA, GAMMA, OMEGA, CHI,
         PHI] = createVliegMatrices(pos.alpha, pos.delta, pos.gamma, pos.omega,
                                    pos.chi, pos.phi)
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD,
            self._getTau() * TORAD)

        S = TAU * SIGMA
        y_vector = matrix([[0], [1], [0]])

        # Calculate Bin from equation 15:
        surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
        incoming_alpha = ALPHA.I * y_vector
        minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
        Bin = asin(bound(-minusSinBetaIn))

        # Calculate Bout from equation 16:
        #  surfacenormal_alpha has just ben calculated
        outgoing_alpha = DELTA * GAMMA * y_vector
        sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
        Bout = asin(bound(sinBetaOut))

        # Calculate 2theta from equation 25:

        cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
        twotheta = acos(bound(cosTwoTheta))
        psi = self._anglesToPsi(pos, wavelength)

        return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
Esempio n. 24
0
    def _findMatrixToTransformAIntoB(self, a, b):
        """
        Finds a particular matrix Mo that transforms the unit vector a into the
        unit vector b. Thats is it finds Mo Mo*a=b. a and b 3x1 matrixes and Mo
        is a 3x3 matrix.

        Throws an exception if this is not possible.
            """
        # Maths from the appendix of "Angle caluculations
        # for a 5-circle diffractometer used for surface X-ray diffraction",
        # E. Vlieg, J.F. van der Veen, J.E. Macdonald and M. Miller, J. of
        # Applied Cryst. 20 (1987) 330.
        #                                       - courtesy of Elias Vlieg again

        # equation A2: compute angle xi between vectors a and b
        cosxi = dot3(a, b)
        try:
            cosxi = bound(cosxi)
        except ValueError:
            raise Exception("Could not compute cos(xi), vectors a=%f and b=%f "
                            "must be of unit length" % (norm(a), norm(b)))
        xi = acos(cosxi)

        # Mo is identity matrix if xi zero (math below would blow up)
        if abs(xi) < 1e-10:
            return I

        # equation A3: c=cross(a,b)/sin(xi)
        c = cross3(a, b) * (1 / sin(xi))

        # equation A4: find D matrix that transforms a into the frame
        # x = a; y = c x a; z = c. */
        a1 = a[0, 0]
        a2 = a[1, 0]
        a3 = a[2, 0]
        c1 = c[0, 0]
        c2 = c[1, 0]
        c3 = c[2, 0]
        D = matrix([[a1, a2, a3],
                    [c2 * a3 - c3 * a2, c3 * a1 - c1 * a3, c1 * a2 - c2 * a1],
                    [c1, c2, c3]])

        # equation A5: create Xi to rotate by xi about z-axis
        XI = matrix([[cos(xi), -sin(xi), 0],
                     [sin(xi), cos(xi), 0],
                     [0, 0, 1]])

        # eq A6: compute Mo
        return D.I * XI * D
Esempio n. 25
0
    def _findMatrixToTransformAIntoB(self, a, b):
        """
        Finds a particular matrix Mo that transforms the unit vector a into the
        unit vector b. Thats is it finds Mo Mo*a=b. a and b 3x1 matrixes and Mo
        is a 3x3 matrix.

        Throws an exception if this is not possible.
            """
        # Maths from the appendix of "Angle caluculations
        # for a 5-circle diffractometer used for surface X-ray diffraction",
        # E. Vlieg, J.F. van der Veen, J.E. Macdonald and M. Miller, J. of
        # Applied Cryst. 20 (1987) 330.
        #                                       - courtesy of Elias Vlieg again

        # equation A2: compute angle xi between vectors a and b
        cosxi = dot3(a, b)
        try:
            cosxi = bound(cosxi)
        except ValueError:
            raise Exception("Could not compute cos(xi), vectors a=%f and b=%f "
                            "must be of unit length" % (norm(a), norm(b)))
        xi = acos(cosxi)

        # Mo is identity matrix if xi zero (math below would blow up)
        if abs(xi) < 1e-10:
            return I

        # equation A3: c=cross(a,b)/sin(xi)
        c = cross3(a, b) * (1 / sin(xi))

        # equation A4: find D matrix that transforms a into the frame
        # x = a; y = c x a; z = c. */
        a1 = a[0, 0]
        a2 = a[1, 0]
        a3 = a[2, 0]
        c1 = c[0, 0]
        c2 = c[1, 0]
        c3 = c[2, 0]
        D = matrix([[a1, a2, a3],
                    [c2 * a3 - c3 * a2, c3 * a1 - c1 * a3, c1 * a2 - c2 * a1],
                    [c1, c2, c3]])

        # equation A5: create Xi to rotate by xi about z-axis
        XI = matrix([[cos(xi), -sin(xi), 0], [sin(xi), cos(xi), 0], [0, 0, 1]])

        # eq A6: compute Mo
        return D.I * XI * D
Esempio n. 26
0
 def calc_miscut(self, h, k, l, pos):
     """
     Calculate miscut angle and axis that matches
     given hkl position and diffractometer angles
     """
     q_vec = self._strategy.calculate_q_phi(pos)
     hkl_nphi = self._UB * matrix([[h], [k], [l]])
     axis = self._tobj.transform(cross3(q_vec, hkl_nphi), True)
     norm_axis = norm(axis)
     if norm_axis < SMALL:
         return None, None
     axis = axis / norm(axis)
     try:
         miscut = acos(
             bound(dot3(q_vec, hkl_nphi) /
                   (norm(q_vec) * norm(hkl_nphi)))) * TODEG
     except AssertionError:
         return None, None
     return miscut, axis.T.tolist()[0]
Esempio n. 27
0
    def simulateMoveTo(self, newpos):

        pos = self.diffhw.getPosition()  # a tuple
        (hkl_pos , _) = self._diffcalc.angles_to_hkl(pos)

        nref_hkl = [i[0] for i in self._diffcalc._ub.ubcalc.n_hkl.tolist()]
        pol, az_nref, sc = self._diffcalc._ub.ubcalc.calc_offset_for_hkl(hkl_pos, nref_hkl)
        if pol < SMALL:
            az_nref = 0
        sc_nref_hkl = [sc * v for v in nref_hkl]

        _ubm = self._diffcalc._ub.ubcalc._get_UB()
        qvec = _ubm * matrix(hkl_pos).T
        qvec_rlu = sqrt(dot3(qvec, qvec)) * self._diffcalc._ub.ubcalc.get_hkl_plane_distance(nref_hkl) / (2.*pi)

        try:
            newpol = acos(bound(newpos / qvec_rlu))
        except AssertionError:
            raise DiffcalcException("Scattering vector projection value  of %.5f r.l.u. unreachable." % newpos)

        try:
            hkl_offset = self._diffcalc._ub.ubcalc.calc_hkl_offset(*sc_nref_hkl, pol=newpol, az=az_nref)
            (pos, params) = self._diffcalc.hkl_to_angles(*hkl_offset)
        except DiffcalcException as e:
            if DEBUG:
                raise
            else:
                raise DiffcalcException(e.message)

        width = max(len(k) for k in (params.keys() + list(self.diffhw.getInputNames())))
        fmt = '  %' + str(width) + 's : % 9.4f'

        lines = ['simulated hkl: %9.4f  %.4f  %.4f' % (hkl_offset[0],hkl_offset[1],hkl_offset[2]),
                 self.diffhw.getName() + ' would move to:']
        for idx, name in enumerate(self.diffhw.getInputNames()):
            lines.append(fmt % (name, pos[idx]))
        lines[-1] = lines[-1] + '\n'
        for k in sorted(params):
            lines.append(fmt % (k, params[k]))
        return '\n'.join(lines)
Esempio n. 28
0
def _mu_and_qaz_from_eta_chi_phi(eta, chi, phi, theta, h_phi):
    
    h_phi_norm = normalised(h_phi)                                    # (68,69) 
    h1, h2, h3 = h_phi_norm[0, 0], h_phi_norm[1, 0], h_phi_norm[2, 0]
    a = sin(chi) * h2 * sin(phi) + sin(chi) * h1 * cos(phi) - cos(chi) * h3
    b = (- cos(chi) * sin(eta) * h2 * sin(phi)
         - cos(eta) * h1 * sin(phi) + cos(eta) * h2 * cos(phi)
         - cos(chi) * sin(eta) * h1 * cos(phi)
         - sin(chi) * sin(eta) * h3)
    c = -sin(theta)
    sin_bit = bound(c / sqrt(a * a + b * b))
    mu1 = asin(sin_bit) - atan2(b, a)
    mu2 = pi - asin(sin_bit) - atan2(b, a)

    mu1 = cut_at_minus_pi(mu1)
    mu2 = cut_at_minus_pi(mu2)
    
    # TODO: This special case should be *removed* when the gernal case has shown
    # toencompass it. It exists as fallback for a particular i16 experiment in
    # May 2013 --RobW.
#     if eta == chi == 0:
#         logger.debug("Testing against simplified equations for eta == chi == 0")
#         a = - h3
#         b = - h1 * sin(phi) + h2 * cos(phi)
#         sin_bit = bound(c / sqrt(a * a + b * b))
#         mu_simplified = pi - asin(sin_bit) - atan2(b, a)
#         mu_simplified = cut_at_minus_pi(mu_simplified)
#         if not ne(mu_simplified, mu):
#             raise AssertionError("mu_simplified != mu , %f!=%f" % (mu_simplified, mu))
        
    
    [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu1, None, None, eta, chi, phi)
    h_lab = MU * ETA * CHI * PHI * h_phi                                 # (11)
    qaz1 = atan2(h_lab[0, 0] , h_lab[2, 0])

    [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu2, None, None, eta, chi, phi)
    h_lab = MU * ETA * CHI * PHI * h_phi                                 # (11)
    qaz2 = atan2(h_lab[0, 0] , h_lab[2, 0])

    return (mu1, qaz1) , (mu2, qaz2)
Esempio n. 29
0
def _mu_and_qaz_from_eta_chi_phi(eta, chi, phi, theta, h_phi):
    
    h_phi_norm = normalised(h_phi)                                    # (68,69) 
    h1, h2, h3 = h_phi_norm[0, 0], h_phi_norm[1, 0], h_phi_norm[2, 0]
    a = sin(chi) * h2 * sin(phi) + sin(chi) * h1 * cos(phi) - cos(chi) * h3
    b = (- cos(chi) * sin(eta) * h2 * sin(phi)
         - cos(eta) * h1 * sin(phi) + cos(eta) * h2 * cos(phi)
         - cos(chi) * sin(eta) * h1 * cos(phi)
         - sin(chi) * sin(eta) * h3)
    c = -sin(theta)
    sin_bit = bound(c / sqrt(a * a + b * b))
    mu1 = asin(sin_bit) - atan2(b, a)
    mu2 = pi - asin(sin_bit) - atan2(b, a)

    mu1 = cut_at_minus_pi(mu1)
    mu2 = cut_at_minus_pi(mu2)
    
    # TODO: This special case should be *removed* when the gernal case has shown
    # toencompass it. It exists as fallback for a particular i16 experiment in
    # May 2013 --RobW.
#     if eta == chi == 0:
#         logger.debug("Testing against simplified equations for eta == chi == 0")
#         a = - h3
#         b = - h1 * sin(phi) + h2 * cos(phi)
#         sin_bit = bound(c / sqrt(a * a + b * b))
#         mu_simplified = pi - asin(sin_bit) - atan2(b, a)
#         mu_simplified = cut_at_minus_pi(mu_simplified)
#         if not ne(mu_simplified, mu):
#             raise AssertionError("mu_simplified != mu , %f!=%f" % (mu_simplified, mu))
        
    
    [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu1, None, None, eta, chi, phi)
    h_lab = MU * ETA * CHI * PHI * h_phi                                 # (11)
    qaz1 = atan2(h_lab[0, 0] , h_lab[2, 0])

    [MU, _, _, ETA, CHI, PHI] = create_you_matrices(mu2, None, None, eta, chi, phi)
    h_lab = MU * ETA * CHI * PHI * h_phi                                 # (11)
    qaz2 = atan2(h_lab[0, 0] , h_lab[2, 0])

    return (mu1, qaz1) , (mu2, qaz2)
Esempio n. 30
0
    def _hklToAngles(self, h, k, l, wavelength):
        """
        Calculate position and virtual angles in radians for a given hkl.
        """

        H_phi = self._UB * matrix([[h], [k], [l]])  # units: 1/Angstrom
        H_phi = H_phi / (2 * pi / wavelength)  # units: 2*pi/wavelength
        h_phi = H_phi[0, 0]
        k_phi = H_phi[1, 0]
        l_phi = H_phi[2, 0]  # (5)

        ### determine betain (omegah) and betaout ###

        if not self.constraints.reference:
            raise ValueError("No reference constraint has been constrained.")

        ref_name, ref_value = self.constraints.reference.items()[0]
        if ref_value is not None:
            ref_value *= TORAD
        if ref_name == 'betain':
            betain = ref_value
            betaout = asin(bound(l_phi - sin(betain)))  # (53)
        elif ref_name == 'betaout':
            betaout = ref_value
            betain = asin(bound(l_phi - sin(betaout)))  # (54)
        elif ref_name == 'bin_eq_bout':
            betain = betaout = asin(bound(l_phi / 2))  # (55)
        else:
            raise ValueError("Unexpected constraint name'%s'." % ref_name)

        if abs(betain) < SMALL:
            raise DiffcalcException('required betain was 0 degrees (requested '
                                    'q is perpendicular to surface normal)')
        if betain < -SMALL:
            raise DiffcalcException("betain was -ve (%.4f)" % betain)
#        logger.info('betain = %.4f, betaout = %.4f',
#                    betain * TODEG, betaout * TODEG)
        omegah = betain  # (52)

        ### determine H_lab (X, Y and Z) ###

        Y = -(h_phi**2 + k_phi**2 + l_phi**2) / 2  # (45)

        Z = (sin(betaout) + sin(betain) * (Y + 1)) / cos(omegah)  # (47)

        X_squared = (h_phi**2 + k_phi**2 -
                     ((cos(betain) * Y + sin(betain) * Z)**2))  # (48)
        if (X_squared < 0) and (abs(X_squared) < SMALL):
            X_squared = 0
        Xpositive = sqrt(X_squared)
        if CHOOSE_POSITIVE_GAMMA:
            X = -Xpositive
        else:
            X = Xpositive
#        logger.info('H_lab (X,Y,Z) = [%.4f, %.4f, %.4f]', X, Y, Z)
### determine diffractometer angles ###

        gamma = atan2(-X, Y + 1)  # (49)
        if (abs(gamma) < SMALL):
            # degenerate case, only occurs when q || z
            delta = 2 * omegah
        else:
            delta = atan2(Z * sin(gamma), -X)  # (50)
        M = cos(betain) * Y + sin(betain) * Z
        phi = atan2(h_phi * M - k_phi * X, h_phi * X + k_phi * M)  # (51)

        pos = WillmottHorizontalPosition(delta, gamma, omegah, phi)
        virtual_angles = {'betain': betain, 'betaout': betaout}
        return pos, virtual_angles
Esempio n. 31
0
def _theta_and_qaz_from_detector_angles(delta, nu):
    # Equation 19:
    cos_2theta = cos(delta) * cos(nu)
    theta = acos(bound(cos_2theta)) / 2.
    qaz = atan2(tan(delta), sin(nu))
    return theta, qaz
Esempio n. 32
0
    def _hklToAngles(self, h, k, l, wavelength):
        """
        Calculate position and virtual angles in radians for a given hkl.
        """

        H_phi = self._UB * matrix([[h], [k], [l]])  # units: 1/Angstrom
        H_phi = H_phi / (2 * pi / wavelength)       # units: 2*pi/wavelength
        h_phi = H_phi[0, 0]
        k_phi = H_phi[1, 0]
        l_phi = H_phi[2, 0]                                               # (5)

        ### determine betain (omegah) and betaout ###

        if not self.constraints.reference:
            raise ValueError("No reference constraint has been constrained.")

        ref_name, ref_value = self.constraints.reference.items()[0]
        if ref_value is not None:
            ref_value *= TORAD
        if ref_name == 'betain':
            betain = ref_value
            betaout = asin(bound(l_phi - sin(betain)))                   # (53)
        elif ref_name == 'betaout':
            betaout = ref_value
            betain = asin(bound(l_phi - sin(betaout)))                   # (54)
        elif ref_name == 'bin_eq_bout':
            betain = betaout = asin(bound(l_phi / 2))                    # (55)
        else:
            raise ValueError("Unexpected constraint name'%s'." % ref_name)

        if abs(betain) < SMALL:
            raise DiffcalcException('required betain was 0 degrees (requested '
                                    'q is perpendicular to surface normal)')
        if betain < -SMALL:
            raise DiffcalcException("betain was -ve (%.4f)" % betain)
#        logger.info('betain = %.4f, betaout = %.4f',
#                    betain * TODEG, betaout * TODEG)
        omegah = betain                                                  # (52)

        ### determine H_lab (X, Y and Z) ###

        Y = -(h_phi ** 2 + k_phi ** 2 + l_phi ** 2) / 2                  # (45)

        Z = (sin(betaout) + sin(betain) * (Y + 1)) / cos(omegah)         # (47)

        X_squared = (h_phi ** 2 + k_phi ** 2 -
                    ((cos(betain) * Y + sin(betain) * Z) ** 2))          # (48)
        if (X_squared < 0) and (abs(X_squared) < SMALL):
            X_squared = 0
        Xpositive = sqrt(X_squared)
        if CHOOSE_POSITIVE_GAMMA:
            X = -Xpositive
        else:
            X = Xpositive
#        logger.info('H_lab (X,Y,Z) = [%.4f, %.4f, %.4f]', X, Y, Z)
        ### determine diffractometer angles ###

        gamma = atan2(-X, Y + 1)                                         # (49)
        if (abs(gamma) < SMALL):
            # degenerate case, only occurs when q || z
            delta = 2 * omegah
        else:
            delta = atan2(Z * sin(gamma), -X)                            # (50)
        M = cos(betain) * Y + sin(betain) * Z
        phi = atan2(h_phi * M - k_phi * X, h_phi * X + k_phi * M)        # (51)

        pos = WillmottHorizontalPosition(delta, gamma, omegah, phi)
        virtual_angles = {'betain': betain, 'betaout': betaout}
        return pos, virtual_angles