Exemple #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}
Exemple #2
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)
Exemple #3
0
    def repr_lines(self, ub_calculated, WIDTH=9):
        SET_LABEL = ' <- set'
        lines = []
        if self._n_phi_configured is not None:
            nphi_label = SET_LABEL
            nhkl_label = ''
        elif self._n_hkl_configured is not None:
            nphi_label = ''
            nhkl_label = SET_LABEL
        else:
            raise AssertionError("Neither a manual n_phi nor n_hkl is configured")
        
        if ub_calculated:
            lines.append("   n_phi:".ljust(WIDTH) + self._pretty_vector(self.n_phi) + nphi_label)
            lines.append("   n_hkl:".ljust(WIDTH) + self._pretty_vector(self.n_hkl) + nhkl_label)
            rotation_axis = cross3(matrix('0; 0; 1'), self.n_phi)
            if abs(norm(rotation_axis)) < SMALL:
                lines.append("   miscut:".ljust(WIDTH) + "  None")
            else:
                rotation_axis = rotation_axis * (1 / norm(rotation_axis))
                cos_rotation_angle = dot3(matrix('0; 0; 1'), self.n_phi)
                rotation_angle = acos(cos_rotation_angle)
                lines.append("   miscut:")
                lines.append("      angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
                lines.append("      axis:".ljust(WIDTH) + self._pretty_vector(rotation_axis))
 
        else:  # no ub calculated
            if self._n_phi_configured is not None:
                lines.append("   n_phi:".ljust(WIDTH) + self._pretty_vector(self._n_phi_configured) + SET_LABEL)
            elif self._n_hkl_configured is not None:
                lines.append("   n_hkl:".ljust(WIDTH) + self._pretty_vector(self._n_hkl_configured) + SET_LABEL)

        return lines
    def __str__(self):
        lines = []
        if self._n_phi_configured is not None:
            lines.append("configured n_phi: " + self._pretty_vector(self._n_phi_configured))
        elif self._n_hkl_configured is not None:
            lines.append("configured n_hkl: " + self._pretty_vector(self._n_hkl_configured))
        else:
            raise AssertionError("Neither a manual n_phi nor n_hkl is configured")
        lines.append("           n_phi: " + self._pretty_vector(self.n_phi))
        lines.append("           n_hkl: " + self._pretty_vector(self.n_hkl))
        lines.append("")

        rotation_axis = cross3(matrix('0; 0; 1'), self.n_phi)
        if abs(norm(rotation_axis)) < SMALL:
            lines.append("no miscut")
        else:
            rotation_axis = rotation_axis * (1 / norm(rotation_axis))
            cos_rotation_angle = dot3(matrix('0; 0; 1'), self.n_phi)
            rotation_angle = acos(cos_rotation_angle)
            uvw = rotation_axis.T.tolist()[0]
            lines.append("miscut angle   : %.5f deg (phi axis to reference)" % (rotation_angle * TODEG))
            u_repr = (', '.join(['% .5f' % el for el in uvw]))
            lines.append("miscut direction: [%s] (in phi frame)" % u_repr)

        lines.append("")
        lines.append("To change: set n_hkl_configured or n_phi_configured property.")
        return '\n'.join(lines)
Exemple #5
0
    def repr_lines(self, ub_calculated, WIDTH=9, R=None):
        SET_LABEL = ' <- set'
        lines = []
        if self._n_phi_configured is not None:
            nphi_label = SET_LABEL
            nhkl_label = ''
        elif self._n_hkl_configured is not None:
            nphi_label = ''
            nhkl_label = SET_LABEL
        else:
            raise AssertionError(
                "Neither a manual n_phi nor n_hkl is configured")

        if ub_calculated:
            try:
                lines.append("   n_phi:".ljust(WIDTH) +
                             self._pretty_vector(R.I * self.n_phi) +
                             nphi_label)
            except AttributeError:
                lines.append("   n_phi:".ljust(WIDTH) +
                             self._pretty_vector(self.n_phi) + nphi_label)
            lines.append("   n_hkl:".ljust(WIDTH) +
                         self._pretty_vector(self.n_hkl) + nhkl_label)
            try:
                rotation_axis = R.I * cross3(matrix('0; 0; 1'), self.n_phi)
            except AttributeError:
                rotation_axis = cross3(matrix('0; 0; 1'), self.n_phi)
            if abs(norm(rotation_axis)) < SMALL:
                lines.append("   normal:".ljust(WIDTH) + "  None")
            else:
                rotation_axis = rotation_axis * (1 / norm(rotation_axis))
                cos_rotation_angle = dot3(matrix('0; 0; 1'), self.n_phi)
                rotation_angle = acos(cos_rotation_angle)
                lines.append("   normal:")
                lines.append("      angle:".ljust(WIDTH) + "% 9.5f" %
                             (rotation_angle * TODEG))
                lines.append("      axis:".ljust(WIDTH) +
                             self._pretty_vector(rotation_axis))

        else:  # no ub calculated
            if self._n_phi_configured is not None:
                try:
                    lines.append("   n_phi:".ljust(WIDTH) +
                                 self._pretty_vector(R.I *
                                                     self._n_phi_configured) +
                                 SET_LABEL)
                except AttributeError:
                    lines.append("   n_phi:".ljust(WIDTH) +
                                 self._pretty_vector(self._n_phi_configured) +
                                 SET_LABEL)
            elif self._n_hkl_configured is not None:
                lines.append("   n_hkl:".ljust(WIDTH) +
                             self._pretty_vector(self._n_hkl_configured) +
                             SET_LABEL)

        return lines
Exemple #6
0
 def getPosition(self):
     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 = self._diffcalc._ub.ubcalc.calc_offset_for_hkl(hkl_pos, nref_hkl)[0]
     _ubm = self._diffcalc._ub.ubcalc._get_UB()
     qvec = _ubm * matrix(hkl_pos).T
     sc = sqrt(dot3(qvec, qvec)) * self._diffcalc._ub.ubcalc.get_hkl_plane_distance(nref_hkl) / (2.*pi)
     res = sc * cos(pol)
     return res
 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
Exemple #8
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}
Exemple #9
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
Exemple #10
0
    def str_lines_u_angle_and_axis(self):
        lines = []
        fmt = "% 9.5f % 9.5f % 9.5f"
        y = matrix('0; 0; 1')
        rotation_axis = cross3(y, self.U * y)
        if abs(norm(rotation_axis)) < SMALL:
            lines.append("   U angle:".ljust(WIDTH) + "  0")
        else:
            rotation_axis = rotation_axis * (1 / norm(rotation_axis))
            cos_rotation_angle = dot3(y, self.U * y)
            rotation_angle = acos(cos_rotation_angle)

            lines.append("      angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
            lines.append("       axis:".ljust(WIDTH) + fmt % tuple((rotation_axis.T).tolist()[0]))
 
        return lines
Exemple #11
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
    def _fit_ub_matrix_uncon(self, *args):
        if args is None:
            raise DiffcalcException(
                "Please specify list of reference reflection indices.")
        if len(args) < 3:
            raise DiffcalcException(
                "Need at least 3 reference reflections to fit UB matrix.")

        x = []
        y = []
        for idx in args:
            try:
                hkl_vals, pos, en, _, _ = self.get_reflection(idx)
            except IndexError:
                raise DiffcalcException(
                    "Cannot read reflection data for index %s" % str(idx))
            pos.changeToRadians()
            x.append(hkl_vals)
            wl = 12.3984 / en
            y_tmp = self._strategy.calculate_q_phi(pos) * 2. * pi / wl
            y.append(y_tmp.T.tolist()[0])

        xm = matrix(x)
        ym = matrix(y)
        b = (xm.T * xm).I * xm.T * ym

        b1, b2, b3 = matrix(b.tolist()[0]), matrix(b.tolist()[1]), matrix(
            b.tolist()[2])
        e1 = b1 / norm(b1)
        e2 = b2 - e1 * dot3(b2.T, e1.T)
        e2 = e2 / norm(e2)
        e3 = b3 - e1 * dot3(b3.T, e1.T) - e2 * dot3(b3.T, e2.T)
        e3 = e3 / norm(e3)

        new_umatrix = matrix(e1.tolist() + e2.tolist() + e3.tolist()).T

        V = dot3(cross3(b1.T, b2.T), b3.T)
        a1 = cross3(b2.T, b3.T) * 2 * pi / V
        a2 = cross3(b3.T, b1.T) * 2 * pi / V
        a3 = cross3(b1.T, b2.T) * 2 * pi / V
        ax, bx, cx = norm(a1), norm(a2), norm(a3)
        alpha = acos(dot3(a2, a3) / (bx * cx)) * TODEG
        beta = acos(dot3(a1, a3) / (ax * cx)) * TODEG
        gamma = acos(dot3(a1, a2) / (ax * bx)) * TODEG

        lattice_name = self._state.crystal.getLattice()[0]
        return new_umatrix, (lattice_name, ax, bx, cx, alpha, beta, gamma)
Exemple #13
0
    def str_lines_u_angle_and_axis(self):
        lines = []
        fmt = "% 9.5f % 9.5f % 9.5f"
        y = matrix('0; 0; 1')
        rotation_axis = cross3(y, self.U * y)
        if abs(norm(rotation_axis)) < SMALL:
            lines.append("   U angle:".ljust(WIDTH) + "  0")
        else:
            rotation_axis = rotation_axis * (1 / norm(rotation_axis))
            cos_rotation_angle = dot3(y, self.U * y)
            rotation_angle = acos(cos_rotation_angle)

            lines.append("      angle:".ljust(WIDTH) + "% 9.5f" %
                         (rotation_angle * TODEG))
            lines.append("       axis:".ljust(WIDTH) +
                         fmt % tuple((rotation_axis.T).tolist()[0]))

        return lines
 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]
Exemple #15
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)
    def calculate_UB_from_primary_only(self, idx=1):
        """
        Calculate orientation matrix with the shortest absolute angle change.
        Default: use first reflection.
        """

        # Algorithm from http://www.j3d.org/matrix_faq/matrfaq_latest.html

        # Get hkl and angle values for the first two reflections
        if self._state.reflist is None:
            raise DiffcalcException(
                "Cannot calculate a u matrix until a UBCalcaluation has been "
                "started with newub")
        try:
            (h, pos, _, _, _) = self.get_reflection(idx)
        except IndexError:
            raise DiffcalcException(
                "One reflection is required to calculate a u matrix")

        h = matrix([h]).T  # row->column
        pos.changeToRadians()
        B = self._state.crystal.B
        h_crystal = B * h
        h_crystal = h_crystal * (1 / norm(h_crystal))

        q_measured_phi = self._strategy.calculate_q_phi(pos)
        q_measured_phi = q_measured_phi * (1 / norm(q_measured_phi))

        rotation_axis = cross3(h_crystal, q_measured_phi)
        rotation_axis = rotation_axis * (1 / norm(rotation_axis))

        cos_rotation_angle = dot3(h_crystal, q_measured_phi)
        rotation_angle = acos(cos_rotation_angle)

        uvw = rotation_axis.T.tolist()[0]  # TODO: cleanup
        print "resulting U angle: %.5f deg" % (rotation_angle * TODEG)
        u_repr = (', '.join(['% .5f' % el for el in uvw]))
        print "resulting U axis direction: [%s]" % u_repr

        u, v, w = uvw
        rcos = cos(rotation_angle)
        rsin = sin(rotation_angle)
        m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]  # TODO: tidy
        m[0][0] = rcos + u * u * (1 - rcos)
        m[1][0] = w * rsin + v * u * (1 - rcos)
        m[2][0] = -v * rsin + w * u * (1 - rcos)
        m[0][1] = -w * rsin + u * v * (1 - rcos)
        m[1][1] = rcos + v * v * (1 - rcos)
        m[2][1] = u * rsin + w * v * (1 - rcos)
        m[0][2] = v * rsin + u * w * (1 - rcos)
        m[1][2] = -u * rsin + v * w * (1 - rcos)
        m[2][2] = rcos + w * w * (1 - rcos)

        if self._UB is None:
            print "Calculating UB matrix from the first reflection only."
        else:
            print "Recalculating UB matrix from the first reflection only."
        print(
            "NOTE: A new UB matrix will not be automatically calculated "
            "when the orientation reflections are modified.")

        self._U = matrix(m)
        self._UB = self._U * B

        self._state.configure_calc_type(manual_U=self._U, or0=idx)
        self.save()
Exemple #17
0
    def calculate_UB_from_primary_only(self):
        """
        Calculate orientation matrix with the shortest absolute angle change.
        Uses first orientation reflection
        """

        # Algorithm from http://www.j3d.org/matrix_faq/matrfaq_latest.html

        # Get hkl and angle values for the first two refelctions
        if self._state.reflist is None:
            raise DiffcalcException("Cannot calculate a u matrix until a UBCalcaluation has been " "started with newub")
        try:
            (h, pos, _, _, _) = self._state.reflist.getReflection(1)
        except IndexError:
            raise DiffcalcException("One reflection is required to calculate a u matrix")

        h = matrix([h]).T  # row->column
        pos.changeToRadians()
        B = self._state.crystal.B
        h_crystal = B * h
        h_crystal = h_crystal * (1 / norm(h_crystal))

        q_measured_phi = self._strategy.calculate_q_phi(pos)
        q_measured_phi = q_measured_phi * (1 / norm(q_measured_phi))

        rotation_axis = cross3(h_crystal, q_measured_phi)
        rotation_axis = rotation_axis * (1 / norm(rotation_axis))

        cos_rotation_angle = dot3(h_crystal, q_measured_phi)
        rotation_angle = acos(cos_rotation_angle)

        uvw = rotation_axis.T.tolist()[0]  # TODO: cleanup
        print "resulting U angle: %.5f deg" % (rotation_angle * TODEG)
        u_repr = ", ".join(["% .5f" % el for el in uvw])
        print "resulting U axis direction: [%s]" % u_repr

        u, v, w = uvw
        rcos = cos(rotation_angle)
        rsin = sin(rotation_angle)
        m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]  # TODO: tidy
        m[0][0] = rcos + u * u * (1 - rcos)
        m[1][0] = w * rsin + v * u * (1 - rcos)
        m[2][0] = -v * rsin + w * u * (1 - rcos)
        m[0][1] = -w * rsin + u * v * (1 - rcos)
        m[1][1] = rcos + v * v * (1 - rcos)
        m[2][1] = u * rsin + w * v * (1 - rcos)
        m[0][2] = v * rsin + u * w * (1 - rcos)
        m[1][2] = -u * rsin + v * w * (1 - rcos)
        m[2][2] = rcos + w * w * (1 - rcos)

        if self._UB is None:
            print "Calculating UB matrix from the first reflection only."
        else:
            print "Recalculating UB matrix from the first reflection only."
        print (
            "NOTE: A new UB matrix will not be automatically calculated "
            "when the orientation reflections are modified."
        )

        self._state.configure_calc_type(or0=1)

        self._U = matrix(m)
        self._UB = self._U * B

        self.save()