Beispiel #1
0
    def __init__(self, phi0, misset0, phi1, misset1):
        """Initialise the rotation axis and what have you from some
    experimental results. N.B. all input values in DEGREES."""

        # canonical: X = X-ray beam
        #            Z = rotation axis
        #            Y = Z ^ X

        z = matrix.col([0, 0, 1])

        # then calculate the rotation axis

        R = (
            (
                z.axis_and_angle_as_r3_rotation_matrix(phi1, deg=True)
                * matrix.sqr(xyz_matrix(misset1[0], misset1[1], misset1[2]))
            )
            * (
                z.axis_and_angle_as_r3_rotation_matrix(phi0, deg=True)
                * matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2]))
            ).inverse()
        )

        self._z = z
        self._r = matrix.col(r3_rotation_axis_and_angle_from_matrix(R).axis)
        self._M0 = matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2]))

        return
Beispiel #2
0
    def run(self, args=None):
        """Execute the script."""
        # Parse the command line
        params, options = self.parser.parse_args(args, show_diff_phil=True)

        # Check the number of experiments is at least 2
        experiments = flatten_experiments(params.input.experiments)
        if len(experiments) < 2:
            self.parser.print_help()
            return

        detectors = [experiment.detector[0] for experiment in experiments]

        for pair in combinations(detectors, 2):
            determine_axis(pair, params)

        crystals = [experiment.crystal for experiment in experiments]
        goniometers = [experiment.goniometer for experiment in experiments]

        FUs = []

        for c, g in zip(crystals, goniometers):
            u = matrix.sqr(c.get_U())
            f = matrix.sqr(g.get_fixed_rotation())
            FUs.append(f * u)

        for pair in combinations(FUs, 2):
            R = pair[1] * pair[0].inverse()
            rot = r3_rotation_axis_and_angle_from_matrix(R)
            angle = rot.angle(deg=True)
            axis = matrix.col(rot.axis)
            if abs(angle) < 10:
                continue
            print("Axis: %8.5f %8.5f %8.5f" % axis.elems, "angle: %7.4f" % angle)
Beispiel #3
0
    def __init__(self, phi0, misset0, phi1, misset1):
        """Initialise the rotation axis and what have you from some
        experimental results. N.B. all input values in DEGREES."""

        # canonical: X = X-ray beam
        #            Z = rotation axis
        #            Y = Z ^ X

        z = matrix.col([0, 0, 1])

        # then calculate the rotation axis

        R = (
            (
                z.axis_and_angle_as_r3_rotation_matrix(phi1, deg=True)
                * matrix.sqr(xyz_matrix(misset1[0], misset1[1], misset1[2]))
            )
            * (
                z.axis_and_angle_as_r3_rotation_matrix(phi0, deg=True)
                * matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2]))
            ).inverse()
        )

        self._z = z
        self._r = matrix.col(r3_rotation_axis_and_angle_from_matrix(R).axis)
        self._M0 = matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2]))

        return
def difference_rotation_matrix_axis_angle(crystal_a, crystal_b, target_angle=0):
    from cctbx import sgtbx

    # assert crystal_a.get_space_group() == crystal_b.get_space_group()
    space_group = crystal_b.get_space_group()
    best_R_ab = None
    best_cb_op = None
    best_axis = None
    best_angle = 1e8
    # iterate over space group ops to find smallest differences
    for i_op, op in enumerate(space_group.build_derived_laue_group().all_ops()):
        if op.r().determinant() < 0:
            continue
        elif not op.t().is_zero():
            continue
        cb_op = sgtbx.change_of_basis_op(op.inverse())
        crystal_b_sym = crystal_b.change_basis(cb_op)
        U_a = crystal_a.get_U()
        U_b = crystal_b_sym.get_U()
        assert U_a.is_r3_rotation_matrix()
        assert U_b.is_r3_rotation_matrix()
        # the rotation matrix to transform from U_a to U_b
        R_ab = U_b * U_a.transpose()
        axis_angle = r3_rotation_axis_and_angle_from_matrix(R_ab)
        axis = axis_angle.axis
        angle = axis_angle.angle() * 180.0 / math.pi
        for sign in (+1, -1):
            if abs(sign * angle - target_angle) < abs(best_angle - target_angle):
                best_angle = sign * angle
                best_axis = tuple(sign * a for a in axis)
                best_R_ab = R_ab if sign > 0 else R_ab.inverse()
                best_cb_op = cb_op if sign > 0 else cb_op.inverse()

    return best_R_ab, best_axis, best_angle, best_cb_op
def difference_rotation_matrix_axis_angle(crystal_a, crystal_b, target_angle=0):
    from cctbx import sgtbx

    # assert crystal_a.get_space_group() == crystal_b.get_space_group()
    space_group = crystal_b.get_space_group()
    best_R_ab = None
    best_cb_op = None
    best_axis = None
    best_angle = 1e8
    # iterate over space group ops to find smallest differences
    for i_op, op in enumerate(space_group.build_derived_laue_group().all_ops()):
        if op.r().determinant() < 0:
            continue
        elif not op.t().is_zero():
            continue
        cb_op = sgtbx.change_of_basis_op(op.inverse())
        crystal_b_sym = crystal_b.change_basis(cb_op)
        U_a = matrix.sqr(crystal_a.get_U())
        U_b = matrix.sqr(crystal_b_sym.get_U())
        assert U_a.is_r3_rotation_matrix()
        assert U_b.is_r3_rotation_matrix()
        # the rotation matrix to transform from U_a to U_b
        R_ab = U_b * U_a.transpose()
        axis_angle = r3_rotation_axis_and_angle_from_matrix(R_ab)
        axis = axis_angle.axis
        angle = axis_angle.angle() * 180.0 / math.pi
        for sign in (+1, -1):
            if abs(sign * angle - target_angle) < abs(best_angle - target_angle):
                best_angle = sign * angle
                best_axis = tuple(sign * a for a in axis)
                best_R_ab = R_ab if sign > 0 else R_ab.inverse()
                best_cb_op = cb_op if sign > 0 else cb_op.inverse()

    return best_R_ab, best_axis, best_angle, best_cb_op
Beispiel #6
0
def compute_Q(xparm_target, xparm_move):

    _M = determine_rotation_to_dtrek(xparm_target)

    a_t, b_t, c_t = parse_xds_xparm(xparm_target)
    a_m, b_m, c_m = parse_xds_xparm(xparm_move)

    m_t = matrix.sqr(a_t + b_t + c_t)

    min_r = 180.0
    min_ax = None

    for op in ['X,Y,Z', '-X,-Y,Z', '-X,Y,-Z', 'X,-Y,-Z',
               'Z,X,Y', 'Z,-X,-Y', '-Z,-X,Y', '-Z,X,-Y',
               'Y,Z,X', '-Y,Z,-X', 'Y,-Z,-X', '-Y,-Z,X']:
        op_m = op_to_mat(op)
        m_m = op_m * matrix.sqr(a_m + b_m + c_m)
        q = m_t.inverse() * m_m
        if math.fabs(q.determinant() - 1) > 0.1:
            print 'rejected %s' % op
            continue
        q_r = r3_rotation_axis_and_angle_from_matrix(q.inverse())

        if math.fabs(q_r.angle(deg = True)) < min_r:
            if q_r.angle(deg = True) >= 0:
                min_ax = matrix.col(q_r.axis)
                min_r = q_r.angle(deg = True)
            else:
                min_ax = - matrix.col(q_r.axis)
                min_r = - q_r.angle(deg = True)

    return (_M * min_ax).elems, min_r
Beispiel #7
0
    def _reorient_coordinate_frame(self):
        """Align a DIALS experiment and data in a reflection table to the
        PETS coordinate system. In that system, the s0 vector is aligned with
        -Z, while the rotation axis is in the X-Z plane, close to +X"""

        axis = matrix.col(self.experiment.goniometer.get_rotation_axis())
        us0 = matrix.col(self.experiment.beam.get_unit_s0())

        normal = us0.cross(-axis).normalize()
        orthogonalised_axis = us0.cross(normal).normalize()

        # Keep track of s1.us0 values to check reorientation
        s1_dot_us0 = self.reflections["s1"].dot(us0)

        R = align_reference_frame(us0, (0, 0, -1), orthogonalised_axis,
                                  (1, 0, 0))

        axis_angle = r3_rotation_axis_and_angle_from_matrix(R)
        axis = axis_angle.axis
        angle = axis_angle.angle(deg=False)
        logger.info(
            "Rotating experiment about axis ({:.4f}, {:.4f}, {:.4f}) by {:.3f}°"
            .format(*axis, np.degrees(angle)))

        self.experiment.detector.rotate_around_origin(axis, angle, deg=False)
        self.experiment.crystal = rotate_crystal(self.experiment.crystal, R,
                                                 axis, angle)

        # Following does not work (https://github.com/cctbx/dxtbx/issues/454)
        # self.experiment.beam.rotate_around_origin(axis, angle, deg=False)
        # Set unit s0 and polarization normal directly instead (preserving inconsistent
        # beam, if that's what we have).
        new_us0 = (R *
                   matrix.col(self.experiment.beam.get_unit_s0())).normalize()
        new_p_norm = (R * matrix.col(
            self.experiment.beam.get_polarization_normal())).normalize()
        self.experiment.beam.set_unit_s0(new_us0)
        self.experiment.beam.set_polarization_normal(new_p_norm)

        # Rotating the goniometer is also complicated. See https://github.com/cctbx/dxtbx/pull/451
        new_datum = (R * matrix.col(
            self.experiment.goniometer.get_rotation_axis_datum())).normalize()
        new_F = (R *
                 matrix.sqr(self.experiment.goniometer.get_fixed_rotation()) *
                 R.transpose())
        new_S = (
            R * matrix.sqr(self.experiment.goniometer.get_setting_rotation()) *
            R.transpose())
        self.experiment.goniometer.set_rotation_axis_datum(new_datum)
        self.experiment.goniometer.set_setting_rotation(new_S)
        self.experiment.goniometer.set_fixed_rotation(new_F)

        # Re-calculate s1 vectors and reciprocal lattice points with new geometry
        el = ExperimentList()
        el.append(self.experiment)
        self.reflections.map_centroids_to_reciprocal_space(el, calculated=True)

        error = flex.abs(s1_dot_us0 - self.reflections["s1"].dot(new_us0))
        if flex.max(error) > 1e-10:
            raise RuntimeError("Failed to rotate experiment correctly")
Beispiel #8
0
def derive_axis_angle(xparm0, xparm1):
  xparm0 = find_xparm(xparm0)
  xparm1 = find_xparm(xparm1)
  from scitbx.math import r3_rotation_axis_and_angle_from_matrix
  import math
  ub0 = xparm_to_ub(xparm0)
  ub1 = xparm_to_ub(xparm1)
  R = ub1 * ub0.inverse()
  axis_angle = r3_rotation_axis_and_angle_from_matrix(R)
  axis = axis_angle.axis
  angle = axis_angle.angle() * 180.0 / math.pi
  return axis, angle, R
Beispiel #9
0
def determine_effective_scan_axis(gonio):
    x = gonio.rotate_vector(0.0, 1, 0, 0)
    y = gonio.rotate_vector(0.0, 0, 1, 0)
    z = gonio.rotate_vector(0.0, 0, 0, 1)

    R = matrix.rec(x + y + z, (3, 3)).transpose()

    x1 = gonio.rotate_vector(1.0, 1, 0, 0)
    y1 = gonio.rotate_vector(1.0, 0, 1, 0)
    z1 = gonio.rotate_vector(1.0, 0, 0, 1)

    R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose()

    RA = R1 * R.inverse()

    rot = r3_rotation_axis_and_angle_from_matrix(RA)

    return rot.axis, rot.angle(deg = True)
def cbf_gonio_to_effective_axis_fixed_old(cbf_gonio):
  '''Given a cbf goniometer handle, first determine the real rotation
  axis, then determine the fixed component of rotation which is rotated
  about this axis.'''

  # First construct the real rotation axis, as the difference in rotating
  # the identity matrix at the end of the scan and the beginning.

  x = cbf_gonio.rotate_vector(0.0, 1, 0, 0)
  y = cbf_gonio.rotate_vector(0.0, 0, 1, 0)
  z = cbf_gonio.rotate_vector(0.0, 0, 0, 1)

  R = matrix.rec(x + y + z, (3, 3)).transpose()

  x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0)
  y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0)
  z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1)

  R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose()

  RA = R1 * R.inverse()

  rot = r3_rotation_axis_and_angle_from_matrix(RA)

  # Then, given this, determine the component of the scan which is fixed -
  # which will need to be with respect to the unrotated axis. N.B. this
  # will not be unique, but should be correct modulo a free rotation about
  # the shifted axis.

  start = cbf_gonio.get_rotation_range()[0]

  # want positive rotations => if negative invert axis
  axis = matrix.col(rot.axis)
  angle = rot.angle()
  if angle < 0:
    axis = -1 * axis
    # common sense would suggest in here that if the angle is -ve should
    # be made +ve - works OK for omega scans but not phi scans, probably
    # incomplete goniometer definition problem...
    # start = -start

  S = axis.axis_and_angle_as_r3_rotation_matrix(start, deg=True)

  return axis, S.inverse() * R
Beispiel #11
0
def cbf_gonio_to_effective_axis_fixed_old(cbf_gonio):
    '''Given a cbf goniometer handle, first determine the real rotation
  axis, then determine the fixed component of rotation which is rotated
  about this axis.'''

    # First construct the real rotation axis, as the difference in rotating
    # the identity matrix at the end of the scan and the beginning.

    x = cbf_gonio.rotate_vector(0.0, 1, 0, 0)
    y = cbf_gonio.rotate_vector(0.0, 0, 1, 0)
    z = cbf_gonio.rotate_vector(0.0, 0, 0, 1)

    R = matrix.rec(x + y + z, (3, 3)).transpose()

    x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0)
    y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0)
    z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1)

    R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose()

    RA = R1 * R.inverse()

    rot = r3_rotation_axis_and_angle_from_matrix(RA)

    # Then, given this, determine the component of the scan which is fixed -
    # which will need to be with respect to the unrotated axis. N.B. this
    # will not be unique, but should be correct modulo a free rotation about
    # the shifted axis.

    start = cbf_gonio.get_rotation_range()[0]

    # want positive rotations => if negative invert axis
    axis = matrix.col(rot.axis)
    angle = rot.angle()
    if angle < 0:
        axis = -1 * axis
        # common sense would suggest in here that if the angle is -ve should
        # be made +ve - works OK for omega scans but not phi scans, probably
        # incomplete goniometer definition problem...
        # start = -start

    S = axis.axis_and_angle_as_r3_rotation_matrix(start, deg=True)

    return axis, S.inverse() * R
Beispiel #12
0
    def run(self):
        '''Execute the script.'''
        from dials.util.options import flatten_experiments

        # Parse the command line
        params, options = self.parser.parse_args(show_diff_phil=True)

        # Check the number of experiments is at least 2
        experiments = flatten_experiments(params.input.experiments)
        if len(experiments) < 2:
            self.parser.print_help()
            return

        detectors = [experiment.detector[0] for experiment in experiments]

        from itertools import combinations

        for pair in combinations(detectors, 2):
            determine_axis(pair, params)

        from scitbx import matrix
        from scitbx.math import r3_rotation_axis_and_angle_from_matrix

        crystals = [experiment.crystal for experiment in experiments]
        goniometers = [experiment.goniometer for experiment in experiments]

        FUs = []

        for c, g in zip(crystals, goniometers):
            u = matrix.sqr(c.get_U())
            f = matrix.sqr(g.get_fixed_rotation())
            FUs.append(f * u)

        for pair in combinations(FUs, 2):
            R = pair[1] * pair[0].inverse()
            rot = r3_rotation_axis_and_angle_from_matrix(R)
            angle = rot.angle(deg=True)
            axis = matrix.col(rot.axis)
            if abs(angle) < 10:
                continue
            print('Axis: %8.5f %8.5f %8.5f' % axis.elems,
                  'angle: %7.4f' % angle)
Beispiel #13
0
def cbf_gonio_to_effective_axis(cbf_gonio):
  '''Given a cbf goniometer handle, determine the real rotation axis.'''

  x = cbf_gonio.rotate_vector(0.0, 1, 0, 0)
  y = cbf_gonio.rotate_vector(0.0, 0, 1, 0)
  z = cbf_gonio.rotate_vector(0.0, 0, 0, 1)

  R = matrix.rec(x + y + z, (3, 3)).transpose()

  x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0)
  y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0)
  z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1)

  R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose()

  RA = R1 * R.inverse()

  axis = r3_rotation_axis_and_angle_from_matrix(RA).axis

  return axis
Beispiel #14
0
def cbf_gonio_to_effective_axis(cbf_gonio):
    '''Given a cbf goniometer handle, determine the real rotation axis.'''

    x = cbf_gonio.rotate_vector(0.0, 1, 0, 0)
    y = cbf_gonio.rotate_vector(0.0, 0, 1, 0)
    z = cbf_gonio.rotate_vector(0.0, 0, 0, 1)

    R = matrix.rec(x + y + z, (3, 3)).transpose()

    x1 = cbf_gonio.rotate_vector(1.0, 1, 0, 0)
    y1 = cbf_gonio.rotate_vector(1.0, 0, 1, 0)
    z1 = cbf_gonio.rotate_vector(1.0, 0, 0, 1)

    R1 = matrix.rec(x1 + y1 + z1, (3, 3)).transpose()

    RA = R1 * R.inverse()

    axis = r3_rotation_axis_and_angle_from_matrix(RA).axis

    return axis
Beispiel #15
0
def align_experiments(
    experiments: ExperimentList,
    params: libtbx.phil.scope_extract,
) -> ExperimentList:

    if len(experiments) > 1:
        logger.info(
            "Only the first experiment will be used to determine the detector axes"
        )
    expt = experiments[0]
    detector = expt.detector
    if len(detector) > 1:
        logger.info(
            "Only the first panel will be used to determine the detector axes")
    panel = detector[0]

    xds_x, xds_y = read_xds_inp(params.input.xds_inp)
    R = align_reference_frame(panel.get_fast_axis(), xds_x,
                              panel.get_slow_axis(), xds_y)

    axis_angle = r3_rotation_axis_and_angle_from_matrix(R)
    axis = axis_angle.axis
    angle = axis_angle.angle()
    logger.info(
        f"Rotating experiment{'s' if len(experiments) else ''} about axis {axis} by {np.degrees(angle)}°"
    )

    for expt in experiments:
        expt.detector.rotate_around_origin(axis, angle, deg=False)
        expt.beam.rotate_around_origin(axis, angle, deg=False)
        # https://github.com/cctbx/dxtbx/issues/447
        # expt.goniometer.rotate_around_origin(axis, angle, deg=False)
        rotation_axis = matrix.col(expt.goniometer.get_rotation_axis())
        expt.goniometer.set_rotation_axis(R * rotation_axis)
        if expt.crystal is not None:
            expt.crystal = rotate_crystal(expt.crystal, R, axis, angle)

    return experiments
def find_U_matrix(found_vectors, crystal, beam_energy=8, optimise_U=True,
                  refl='orient', angle_accuracy = 0.5):
    """Given a Crystal class object with a cif file loaded into it, this
        function returns the U matrix as a dnp array.

    Args:
        found_vectors: A list of Vector class objects representing the momentum
            transfer vectors of the measured Bragg peaks.

        crystal: A Crystal class object.

        beam_energy: The beam energy in keV.

        optimise_U: If True the function optimises the U matrix before
            returning can be set to False if in Jython because requires scipy.

        refl: The filter applied to the Bragg reflections read from the cif file.

        angle_accuracy: The accuracy required for two angle to be considered equal.

    Returns:
        U: The U matrix as a dnp object.
    """
    # First gets all the allowed momentum transfer vectors of the crystal.
    grouped_reflections = f.group_reflections(crystal, beam_energy, refl=refl)
    all_vectors = []
    for group in grouped_reflections:
        group_vectors = f.momentum_transfer_vectors(group, crystal)
        all_vectors += group_vectors
    # Find the target vectors.
    target_vectors = finding_the_targets(found_vectors, all_vectors, crystal, angle_accuracy)
    found_vectors_copy = copy.deepcopy(found_vectors)
    # Find and apply the first rotation.
    rotation1 = get_rotator(found_vectors[0], target_vectors[0])
    found_vectors = rotate_list(rotation1, found_vectors)

    # Find the second rotation
    rotation2 = get_second_rotator(target_vectors[0], found_vectors[1],
                                      target_vectors[1])

    U = rotation2 * rotation1

    # Optimising the U matrix
    def diff(array, data, vectors):
        """This is a function used to optimise the U matrix. It evaluates the
        difference between the rotated set of vectors and their corosponding
        vectors in reciprical space. 
        """
        x = array[0]
        y = array[1]
        z = array[2]
        angle = array[3]
        axis = Vector([x, y, z])
        U = Rotator(scm.r3_rotation_axis_and_angle_as_matrix(axis, angle))
        data = rotate_list(U, data)
        index_list=[]
        for i, dat in enumerate(data):
            diffs = []
            dat = dat
            for j, vector in enumerate(vectors):
                diffs.append((dat-vector).length())
            index = diffs.index(min(dnp.abs(diffs)))
            index_list.append(index)
        targets = [0]*len(data)
        for i, idx in enumerate(index_list):
            targets[i] = vectors[idx]
        total = 0
        for i, dat in enumerate(data):
            total += dnp.abs((dat - targets[i]).length())
        return total

    if not optimise_U:
        return U
    elif optimise_U:
            # The array gives a first estimate for the arguments for the diff
            # function.
        U_axis_angle = scm.r3_rotation_axis_and_angle_from_matrix(U)
        axis = Vector(U_axis_angle.axis)
        array = dnp.array([axis[0], axis[1], axis[2], U_axis_angle.angle()])
        import scipy.optimize
        optimise = scipy.optimize.minimize(diff, array, (found_vectors_copy,
                                                         all_vectors),
                                           bounds=[(-1, 1), (-1, 1), (-1, 1),
                                                   (-dnp.pi, dnp.pi)])
        if optimise['success']:
            new_axis = Vector((optimise.x[0], optimise.x[1], optimise.x[2]))
            new_U = Rotator(scm.r3_rotation_axis_and_angle_as_matrix(new_axis,
                            optimise.x[3]))
            return new_U
        else:
            print optimise
            print diff(array, found_vectors_copy, all_vectors)
            new_axis = Vector((optimise.x[0], optimise.x[1], optimise.x[2]))
            new_U = Rotator(scm.r3_rotation_axis_and_angle_as_matrix(new_axis,
                            optimise.x[3]))
            new_U_axis_angle = scm.r3_rotation_axis_and_angle_from_matrix(
                new_U)
            array = dnp.array([new_axis[0], new_axis[1], new_axis[2],
                               new_U_axis_angle.angle()])
            print 'U matrix optimisation failed.'
            return U
    else:
        raise Exception("""optimise_U must be a boolean type""")
Beispiel #17
0
def run(args):
  import libtbx.load_env
  from scitbx import matrix
  from cctbx.sgtbx import lattice_symmetry_group
  from scitbx.math import r3_rotation_axis_and_angle_from_matrix

  usage = "%s [options] experiment_0.json ..." % \
    libtbx.env.dispatcher_name

  parser = OptionParser(
    usage=usage,
    phil=phil_scope,
    read_experiments=True,
    check_format=False,
    epilog=help_message)

  params, options = parser.parse_args(show_diff_phil=True)
  experiments = params.input.experiments

  # check input
  space_group = None
  for experiment in experiments:
    assert(len(experiment.data.goniometers()) == 1)
    assert(len(experiment.data.crystals()) == 1)
    crystal = experiment.data.crystals()[0]
    if space_group is None:
      space_group = crystal.get_space_group()
    else:
      assert(crystal.get_space_group() == space_group)

  reference_U = None
  reference_space_group = None

  for j, experiment in enumerate(experiments):
    goniometer = experiment.data.goniometers()[0]
    F = matrix.sqr(goniometer.get_fixed_rotation())
    crystal = experiment.data.crystals()[0]
    U = matrix.sqr(crystal.get_U())
    B = matrix.sqr(crystal.get_B())
    UB = F * U * B
    UBt = UB.transpose().elems
    a, b, c = matrix.col(UBt[0:3]), matrix.col(UBt[3:6]), matrix.col(UBt[6:9])
    axis = matrix.col(goniometer.get_rotation_axis())
    from math import pi
    r2d = 180 / pi
    abc = [a, b, c]
    abc_names = 'abc'
    distances = [(r2d * (min(axis.angle(_a), pi - axis.angle(_a))), k)
                 for k, _a in enumerate(abc)]
    close = sorted(distances)[0]
    if reference_U is None:
      reference_U = U
      reference_space_group = lattice_symmetry_group(crystal.get_unit_cell(),
                                                     max_delta=0.0)
      print '%s possible lattice ops' % len(reference_space_group.all_ops())

    print 'Experiment %d' % j
    print 'Closest (original) axis: %s* %.2f' % \
      (abc_names[close[1]], close[0])

    results = []
    for op in reference_space_group.all_ops():
      R = B * matrix.sqr(op.r().as_double()).transpose() * B.inverse()
      relative = (U * R).inverse() * reference_U
      rot = r3_rotation_axis_and_angle_from_matrix(relative)
      results.append((abs(rot.angle()), op.r().as_hkl(), rot))
    results.sort()
    print 'Best reindex op for experiment %d: %12s (%.3f)' % \
      (j, results[0][1], 180.0 * results[0][2].angle() / pi)

    if results[0][0] > (5 * pi / 180.0):
      print 'Rotation: axis: %.4f %.4f %.4f' % results[0][2].axis
      print '          angle: %.4f degrees' % \
        (180.0 * results[0][2].angle() / pi)
Beispiel #18
0
def run(args):
    import libtbx.load_env
    from scitbx import matrix
    from cctbx.sgtbx import lattice_symmetry_group
    from scitbx.math import r3_rotation_axis_and_angle_from_matrix

    usage = "%s [options] experiment_0.expt ..." % libtbx.env.dispatcher_name

    parser = OptionParser(
        usage=usage,
        phil=phil_scope,
        read_experiments=True,
        check_format=False,
        epilog=help_message,
    )

    params, options = parser.parse_args(show_diff_phil=True)
    experiments = params.input.experiments

    # check input
    space_group = None
    for experiment in experiments:
        assert len(experiment.data.goniometers()) == 1
        assert len(experiment.data.crystals()) == 1
        crystal = experiment.data.crystals()[0]
        if space_group is None:
            space_group = crystal.get_space_group()
        else:
            assert crystal.get_space_group() == space_group

    reference_U = None
    reference_space_group = None

    for j, experiment in enumerate(experiments):
        goniometer = experiment.data.goniometers()[0]
        F = matrix.sqr(goniometer.get_fixed_rotation())
        crystal = experiment.data.crystals()[0]
        U = matrix.sqr(crystal.get_U())
        B = matrix.sqr(crystal.get_B())
        UB = F * U * B
        UBt = UB.transpose().elems
        a, b, c = matrix.col(UBt[0:3]), matrix.col(UBt[3:6]), matrix.col(
            UBt[6:9])
        axis = matrix.col(goniometer.get_rotation_axis())
        from math import pi

        r2d = 180 / pi
        abc = [a, b, c]
        abc_names = "abc"
        distances = [(r2d * (min(axis.angle(_a), pi - axis.angle(_a))), k)
                     for k, _a in enumerate(abc)]
        close = sorted(distances)[0]
        if reference_U is None:
            reference_U = U
            reference_space_group = lattice_symmetry_group(
                crystal.get_unit_cell(), max_delta=0.0)
            print("%s possible lattice ops" %
                  len(reference_space_group.all_ops()))

        print("Experiment %d" % j)
        print("Closest (original) axis: %s* %.2f" %
              (abc_names[close[1]], close[0]))

        results = []
        for op in reference_space_group.all_ops():
            R = B * matrix.sqr(op.r().as_double()).transpose() * B.inverse()
            relative = (U * R).inverse() * reference_U
            rot = r3_rotation_axis_and_angle_from_matrix(relative)
            results.append((abs(rot.angle()), op.r().as_hkl(), rot))
        results.sort()
        print("Best reindex op for experiment %d: %12s (%.3f)" %
              (j, results[0][1], 180.0 * results[0][2].angle() / pi))

        if results[0][0] > (5 * pi / 180.0):
            print("Rotation: axis: %.4f %.4f %.4f" % results[0][2].axis)
            print("          angle: %.4f degrees" %
                  (180.0 * results[0][2].angle() / pi))
def find_U_matrix(found_vectors, crystal, beam_energy=8, optimise_U=True):
    """Given a Crystal class object with a cif file loaded into it, this
        function returns the U matrix as a dnp array.

    Args:
        found_vectors: A list of Vector class objects representing the momentum
            transfer vectors of the measured Bragg peaks.

        crystal: A Crystal class object.

        beam_energy: The beam energy in keV.

        optimise_U: If True the function optimises the U matrix before
            returning can be set to False if in Jython because requires scipy.

    Returns:
        U: The U matrix as a dnp object.
    """
    # First gets all the allowed momentum transfer vectors of the crystal.
    grouped_reflections = f.group_reflections(crystal, beam_energy)
    all_vectors = []
    for group in grouped_reflections:
        group_vectors = f.momentum_transfer_vectors(group, crystal)
        all_vectors += group_vectors
    # Find the target vectors.
    target_vectors = finding_the_targets(found_vectors, all_vectors)
    found_vectors_copy = copy.deepcopy(found_vectors)
    
    U = Rotator((1,0,0,0,1,0,0,0,1))
    print U
    
    # Optimising the U matrix
    def diff(array, data, vectors):
        """This is a function used to optimise the U matrix. It evaluates
        """
        x = array[0]
        y = array[1]
        z = array[2]
#         z = 1.0
        angle = array[3]
        axis = Vector([x, y, z])
        U = Rotator(scm.r3_rotation_axis_and_angle_as_matrix(axis, angle))
        data = rotate_list(U, data)
        index_list=[]
        for i, dat in enumerate(data):
            diffs = []
            dat = dat
            for j, vector in enumerate(vectors):
                diffs.append((dat-vector).length())
            index = diffs.index(min(dnp.abs(diffs)))
            index_list.append(index)
        targets = [0]*len(data)
        for i, idx in enumerate(index_list):
            targets[i] = vectors[idx]
        total = 0
        for i, dat in enumerate(data):
            total += (dat - targets[i]).length()
        return total*1000

    if not optimise_U:
        return U
    elif optimise_U:
        U_axis_angle = scm.r3_rotation_axis_and_angle_from_matrix(U)
        axis = Vector(U_axis_angle.axis)
        # The array gives a first estimate for the arguments for the diff
            # function.
        array = dnp.array([axis[0], axis[1], axis[2], U_axis_angle.angle()])
        print 'old diff', diff(array, found_vectors_copy, all_vectors)
        import scipy.optimize
        optimise = scipy.optimize.basinhopping(diff, array, minimizer_kwargs={'args':(found_vectors_copy, 
            all_vectors)})
        print optimise

        new_axis = Vector((optimise.x[0], optimise.x[1], optimise.x[2]))
        new_U = Rotator(scm.r3_rotation_axis_and_angle_as_matrix(new_axis.normalize(),
                        optimise.x[3]))
        new_U_axis_angle = scm.r3_rotation_axis_and_angle_from_matrix(
            new_U)
        print 'new diff', diff(optimise, found_vectors_copy, all_vectors)
        print 'old ax', axis
        print 'new ax',new_axis
        return new_U
    else:
        raise Exception("""optimise_U must be a boolean type""")