def calc_offset_for_hkl(self, hkl_offset, hkl_ref): """ Calculate polar and azimuthal angles and scaling factor relating offset and reference hkl values """ d_ref = self._state.crystal.get_hkl_plane_distance(hkl_ref) hklref_nphi = self._UB * matrix([[hkl_ref[0]], [hkl_ref[1]], [hkl_ref[2]]]) d_offset = self._state.crystal.get_hkl_plane_distance(hkl_offset) hkloff_nphi = self._UB * matrix([[hkl_offset[0]], [hkl_offset[1]], [hkl_offset[2]]]) sc = d_ref / d_offset par_ref_off = cross3(hklref_nphi, hkloff_nphi) if norm3(par_ref_off) < SMALL: return 0, float('nan'), sc y_axis = cross3(hklref_nphi, matrix('0; 1; 0')) if norm3(y_axis) < SMALL: y_axis = cross3(hklref_nphi, matrix('0; 0; 1')) x_axis = cross3(y_axis, hklref_nphi) x_coord = cos(angle_between_vectors(hkloff_nphi, x_axis)) y_coord = cos(angle_between_vectors(hkloff_nphi, y_axis)) pol = angle_between_vectors(hklref_nphi, hkloff_nphi) if abs(y_coord) < SMALL and abs(x_coord) < SMALL: # Set azimuthal rotation matrix to identity az = 0 else: az = atan2(y_coord, x_coord) return pol, az, sc
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
def _calc_N(Q, n): """Return N as described by Equation 31""" Q = normalised(Q) n = normalised(n) if is_small(angle_between_vectors(Q, n)): raise ValueError('Q and n are parallel and cannot be used to create ' 'an orthonormal matrix') Qxn = cross3(Q, n) QxnxQ = cross3(Qxn, Q) QxnxQ = normalised(QxnxQ) Qxn = normalised(Qxn) return matrix([[Q[0, 0], QxnxQ[0, 0], Qxn[0, 0]], [Q[1, 0], QxnxQ[1, 0], Qxn[1, 0]], [Q[2, 0], QxnxQ[2, 0], Qxn[2, 0]]])
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)
def calc_hkl_offset(self, h, k, l, pol, az): """ Calculate hkl orientation values that are related to the input hkl values by rotation with a given polar and azimuthal angles """ hkl_nphi = self._UB * matrix([[h], [k], [l]]) y_axis = cross3(hkl_nphi, matrix('0; 1; 0')) if norm3(y_axis) < SMALL: y_axis = cross3(hkl_nphi, matrix('0; 0; 1')) rot_polar = xyz_rotation(y_axis.T.tolist()[0], pol) rot_azimuthal = xyz_rotation(hkl_nphi.T.tolist()[0], az) hklrot_nphi = rot_azimuthal * rot_polar * hkl_nphi hklrot = self._UB.I * hklrot_nphi hkl_list = hklrot.T.tolist()[0] return hkl_list
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 _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)
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
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]]) try: axis = cross3(self._ROT.I * q_vec, self._ROT.I * hkl_nphi) except AttributeError: axis = cross3(q_vec, hkl_nphi) 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]
def str_lines_u_angle_and_axis(self): lines = [] fmt = "% 9.5f % 9.5f % 9.5f" y = matrix('0; 0; 1') try: rotation_axis = cross3(self._ROT * y, self._ROT * self.U * y) except TypeError: rotation_axis = cross3(y, self.U * y) if abs(norm(rotation_axis)) < SMALL: lines.append(" miscut 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(" miscut:") 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_UB(self, h1, h2, u1p, u2p): B = self._state.crystal.B h1c = B * h1 h2c = B * h2 # Create modified unit vectors t1, t2 and t3 in crystal and phi systems t1c = h1c t3c = cross3(h1c, h2c) t2c = cross3(t3c, t1c) t1p = u1p # FIXED from h1c 9July08 t3p = cross3(u1p, u2p) t2p = cross3(t3p, t1p) # ...and nornmalise and check that the reflections used are appropriate SMALL = 1e-4 # Taken from Vlieg's code e = DiffcalcException("Invalid orientation reflection(s)") def normalise(m): d = norm(m) if d < SMALL: raise e return m / d t1c = normalise(t1c) t2c = normalise(t2c) t3c = normalise(t3c) t1p = normalise(t1p) t2p = normalise(t2p) t3p = normalise(t3p) Tc = hstack([t1c, t2c, t3c]) Tp = hstack([t1p, t2p, t3p]) self._state.configure_calc_type(or0=1, or1=2) self._U = Tp * Tc.I self._UB = self._U * B self.save()
def _calc_UB(self, h1, h2, u1p, u2p): B = self._state.crystal.B h1c = B * h1 h2c = B * h2 # Create modified unit vectors t1, t2 and t3 in crystal and phi systems t1c = h1c t3c = cross3(h1c, h2c) t2c = cross3(t3c, t1c) t1p = u1p # FIXED from h1c 9July08 t3p = cross3(u1p, u2p) t2p = cross3(t3p, t1p) # ...and nornmalise and check that the reflections used are appropriate SMALL = 1e-4 # Taken from Vlieg's code def normalise(m): d = norm(m) if d < SMALL: raise DiffcalcException( "Invalid UB reference data. Please check that the specified " "reference reflections/orientations are not parallel.") return m / d t1c = normalise(t1c) t2c = normalise(t2c) t3c = normalise(t3c) t1p = normalise(t1p) t2p = normalise(t2p) t3p = normalise(t3p) Tc = hstack([t1c, t2c, t3c]) Tp = hstack([t1p, t2p, t3p]) self._U = Tp * Tc.I self._UB = self._U * B
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 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 __polar_to_hkl(params): from diffcalc.dc import dcyou as _dc from diffcalc.util import norm3, cross3 import __main__ sc, az = params h, k, l = __main__.hkl.getPosition()[:3] hkl_nphi = _dc._ub.ubcalc._UB * matrix([[h], [k], [l]]) try: h_ref, k_ref, l_ref = _dc._ub.ubcalc.get_reflection(1)[0] ref_nphi = _dc._ub.ubcalc._UB * matrix([[h_ref], [k_ref], [l_ref]]) ref_nphi *= norm3(hkl_nphi) / norm3(ref_nphi) except IndexError: raise DiffcalcException( "Please add one reference reflection into the reflection list.") nphi = _dc._ub.ubcalc.n_phi inplane_vec = cross3(ref_nphi, nphi) inplane_vec *= sqrt(1 - sc**2) * norm3(hkl_nphi) / norm3(inplane_vec) ref_nhkl = _dc._ub.ubcalc._UB.I * ref_nphi h_ref, k_ref, l_ref = ref_nhkl.T.tolist()[0] h_res, k_res, l_res = _dc._ub.ubcalc.calc_hkl_offset( h_ref, k_ref, l_ref, acos(sc), az) return h_res, k_res, l_res
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()
def calculate_UB(self): """ Calculate orientation matrix. Uses first two orientation reflections as in Busang and Levy, but for the diffractometer in Lohmeier and Vlieg. """ # Major variables: # h1, h2: user input reciprical lattice vectors of the two reflections # h1c, h2c: user input vectors in cartesian crystal plane # pos1, pos2: measured diffractometer positions of the two reflections # u1a, u2a: measured reflection vectors in alpha frame # u1p, u2p: measured reflection vectors in phi frame # 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 " "UBCalculation has been started with " "'newub'") try: (h1, pos1, _, _, _) = self._state.reflist.getReflection(1) (h2, pos2, _, _, _) = self._state.reflist.getReflection(2) except IndexError: raise DiffcalcException( "Two reflections are required to calculate a u matrix") h1 = matrix([h1]).T # row->column h2 = matrix([h2]).T pos1.changeToRadians() pos2.changeToRadians() # Compute the two reflections' reciprical lattice vectors in the # cartesian crystal frame B = self._state.crystal.B h1c = B * h1 h2c = B * h2 u1p = self._strategy.calculate_q_phi(pos1) u2p = self._strategy.calculate_q_phi(pos2) # Create modified unit vectors t1, t2 and t3 in crystal and phi systems t1c = h1c t3c = cross3(h1c, h2c) t2c = cross3(t3c, t1c) t1p = u1p # FIXED from h1c 9July08 t3p = cross3(u1p, u2p) t2p = cross3(t3p, t1p) # ...and nornmalise and check that the reflections used are appropriate SMALL = 1e-4 # Taken from Vlieg's code e = DiffcalcException("Invalid orientation reflection(s)") def normalise(m): d = norm(m) if d < SMALL: raise e return m / d t1c = normalise(t1c) t2c = normalise(t2c) t3c = normalise(t3c) t1p = normalise(t1p) t2p = normalise(t2p) t3p = normalise(t3p) Tc = hstack([t1c, t2c, t3c]) Tp = hstack([t1p, t2p, t3p]) self._state.configure_calc_type(or0=1, or1=2) self._U = Tp * Tc.I self._UB = self._U * B self.save()
def calculate_UB(self): """ Calculate orientation matrix. Uses first two orientation reflections as in Busang and Levy, but for the diffractometer in Lohmeier and Vlieg. """ # Major variables: # h1, h2: user input reciprical lattice vectors of the two reflections # h1c, h2c: user input vectors in cartesian crystal plane # pos1, pos2: measured diffractometer positions of the two reflections # u1a, u2a: measured reflection vectors in alpha frame # u1p, u2p: measured reflection vectors in phi frame # 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 " "UBCalculation has been started with " "'newub'" ) try: (h1, pos1, _, _, _) = self._state.reflist.getReflection(1) (h2, pos2, _, _, _) = self._state.reflist.getReflection(2) except IndexError: raise DiffcalcException("Two reflections are required to calculate a u matrix") h1 = matrix([h1]).T # row->column h2 = matrix([h2]).T pos1.changeToRadians() pos2.changeToRadians() # Compute the two reflections' reciprical lattice vectors in the # cartesian crystal frame B = self._state.crystal.B h1c = B * h1 h2c = B * h2 u1p = self._strategy.calculate_q_phi(pos1) u2p = self._strategy.calculate_q_phi(pos2) # Create modified unit vectors t1, t2 and t3 in crystal and phi systems t1c = h1c t3c = cross3(h1c, h2c) t2c = cross3(t3c, t1c) t1p = u1p # FIXED from h1c 9July08 t3p = cross3(u1p, u2p) t2p = cross3(t3p, t1p) # ...and nornmalise and check that the reflections used are appropriate SMALL = 1e-4 # Taken from Vlieg's code e = DiffcalcException("Invalid orientation reflection(s)") def normalise(m): d = norm(m) if d < SMALL: raise e return m / d t1c = normalise(t1c) t2c = normalise(t2c) t3c = normalise(t3c) t1p = normalise(t1p) t2p = normalise(t2p) t3p = normalise(t3p) Tc = hstack([t1c, t2c, t3c]) Tp = hstack([t1p, t2p, t3p]) self._state.configure_calc_type(or0=1, or1=2) self._U = Tp * Tc.I self._UB = self._U * B self.save()
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()