Ejemplo n.º 1
0
  def _start(self):
    import h5py
    self._h5_handle = h5py.File(self.get_image_file(), 'r')

    # names change as to what the sample positioner is called - originally was
    # 'pose' now is 'transformations' - FIXME I should be using the depends_on
    # attribute then I would not care what this is called...

    # compute coordinate frame transformation to imgCIF frame, just for kicks
    entry = self._h5_handle['entry']
    sample = entry['sample']

    if 'pose' in sample:
      self._pose_name = 'pose'
    elif 'transformations' in sample:
      self._pose_name = 'transformations'
    else:
      raise RuntimeError, 'cannot find pose or transformations'

    axis = tuple(sample[self._pose_name]['CBF_axis_omega'].attrs['vector'])

    # NeXus coordinate frame: Z is canonical
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    self._R = align_reference_frame(axis, (1, 0, 0), (0, 0, -1), (0, 0, 1))

    return
Ejemplo n.º 2
0
    def derive_reindex_matrix(self, handle):
        """Derive a reindexing matrix to go from the orientation matrix used
        for XDS integration to the one used for DIALS integration."""
        from scitbx import matrix

        dA = matrix.sqr(self._experiment.crystal.get_A())
        dbeam = matrix.col(
            self._experiment.beam.get_sample_to_source_direction())
        daxis = matrix.col(self._experiment.goniometer.get_rotation_axis())
        n = dbeam.cross(daxis)
        xbeam = matrix.col(handle.beam_vector).normalize()
        xaxis = matrix.col(handle.rotation_axis).normalize()

        # want to align XDS -s0 vector...
        from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

        R = align_reference_frame(-xbeam, dbeam, xaxis, n.cross(dbeam))
        xA = matrix.sqr(handle.unit_cell_a_axis + handle.unit_cell_b_axis +
                        handle.unit_cell_c_axis).inverse()
        xA = R * xA

        # assert that this should just be a simple integer rotation matrix
        # i.e. reassignment of a, b, c so...

        return matrix.sqr([int(round(e)) for e in (dA.inverse() * xA).elems])
Ejemplo n.º 3
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")
Ejemplo n.º 4
0
  def __init__(self, sweep):
    self._sweep = sweep

    # detector dimensions in pixels
    assert(len(self.get_detector()) == 1)
    self.detector_size = map(int, self.get_detector()[0].get_image_size())
    self.fast, self.slow = self.detector_size

    R = align_reference_frame(
        self.get_detector()[0].get_fast_axis(), (1,0,0),
        self.get_detector()[0].get_slow_axis(), (0,1,0))

    self.imagecif_to_xds_transformation_matrix = R

    self.detector_x_axis = (
        R * matrix.col(self.get_detector()[0].get_fast_axis())).elems
    self.detector_y_axis = (
        R * matrix.col(self.get_detector()[0].get_slow_axis())).elems

    F = R * matrix.col(self.get_detector()[0].get_fast_axis())
    S = R * matrix.col(self.get_detector()[0].get_slow_axis())
    N = F.cross(S)
    self.detector_normal = N.elems

    origin = R * matrix.col(self.get_detector()[0].get_origin())

    centre = -(origin - origin.dot(N) * N)
    x = centre.dot(F)
    y = centre.dot(S)

    self.pixel_size = self.get_detector()[0].get_pixel_size()
    f, s = self.pixel_size
    self.detector_distance = origin.dot(N)
    # Need to add 0.5 because XDS seems to do centroids in fortran coords
    self.detector_origin = x/f + 0.5, y/f + 0.5

    # Beam stuff
    self.wavelength = self.get_beam().get_wavelength()
    self.beam_vector = R * matrix.col(self.get_beam().get_direction())
    # just to make sure it is the correct length
    self.beam_vector = self.beam_vector.normalize() / self.wavelength
    self.beam_vector = (- self.beam_vector).elems

    # Scan and goniometer stuff
    self.starting_frame = self.get_scan().get_image_range()[0]
    self.starting_angle = self.get_scan().get_oscillation()[0]
    self.oscillation_range = self.get_scan().get_oscillation()[1]
    self.rotation_axis = (
        R * matrix.col(self.get_goniometer().get_rotation_axis())).elems
    return
Ejemplo n.º 5
0
def derive_reindex_matrix(integrate_hkl, integrate_mtz):
    '''Derive a reindexing matrix to go from the orientation matrix used
  for MOSFLM integration to the one used for XDS integration.'''

    dA = integrate_hkl_to_A_matrix(integrate_hkl)
    dbeam, daxis = get_xds_coordinate_frame(integrate_hkl)
    mbeam, maxis = get_mosflm_coordinate_frame(integrate_mtz)

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    R = align_reference_frame(mbeam, -dbeam, maxis, daxis)
    mA = R * integrate_mtz_to_A_matrix(integrate_mtz)

    # assert that this should just be a simple integer rotation matrix
    # i.e. reassignment of a, b, c so...

    return matrix.sqr(map(int, map(round, (dA.inverse() * mA).elems)))
Ejemplo n.º 6
0
def derive_reindex_matrix(integrate_hkl, integrate_mtz):
  '''Derive a reindexing matrix to go from the orientation matrix used
  for MOSFLM integration to the one used for XDS integration.'''

  dA = integrate_hkl_to_A_matrix(integrate_hkl)
  dbeam, daxis = get_xds_coordinate_frame(integrate_hkl)
  mbeam, maxis = get_mosflm_coordinate_frame(integrate_mtz)

  from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
  R = align_reference_frame(mbeam, - dbeam, maxis, daxis)
  mA = R * integrate_mtz_to_A_matrix(integrate_mtz)

  # assert that this should just be a simple integer rotation matrix
  # i.e. reassignment of a, b, c so...

  from scitbx import matrix
  return matrix.sqr(map(int, map(round, (dA.inverse() * mA).elems)))
Ejemplo n.º 7
0
def derive_reindex_matrix(experiments_json, integrate_hkl):
  '''Derive a reindexing matrix to go from the orientation matrix used
  for XDS integration to the one used for DIALS integration.'''

  dA = get_dials_matrix(experiments_json)
  dbeam, daxis = get_dials_coordinate_frame(experiments_json)
  xbeam, xaxis = get_xds_coordinate_frame(integrate_hkl)

  # want to align XDS -s0 vector...
  from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
  R = align_reference_frame(- xbeam, dbeam, xaxis, daxis)
  xA = R * integrate_hkl_to_A_matrix(integrate_hkl)

  # assert that this should just be a simple integer rotation matrix
  # i.e. reassignment of a, b, c so...

  from scitbx import matrix
  return matrix.sqr(map(int, map(round, (dA.inverse() * xA).elems)))
Ejemplo n.º 8
0
def derive_reindex_matrix(crystal_json, sweep_json, integrate_mtz):
    """Derive a reindexing matrix to go from the orientation matrix used
    for MOSFLM integration to the one used for DIALS integration."""

    dA = get_dials_matrix(crystal_json)
    dbeam, daxis = get_dials_coordinate_frame(sweep_json)
    mbeam, maxis = get_mosflm_coordinate_frame(integrate_mtz)

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

    R = align_reference_frame(mbeam, dbeam, maxis, daxis)
    mA = R * integrate_mtz_to_A_matrix(integrate_mtz)

    # assert that this should just be a simple integer rotation matrix
    # i.e. reassignment of a, b, c so...

    from scitbx import matrix

    return matrix.sqr(map(int, map(round, (dA.inverse() * mA).elems)))
Ejemplo n.º 9
0
def derive_reindex_matrix(crystal_json, sweep_json, integrate_hkl):
    """Derive a reindexing matrix to go from the orientation matrix used
  for XDS integration to the one used for DIALS integration."""

    dA = get_dials_matrix(crystal_json)
    dbeam, daxis = get_dials_coordinate_frame(sweep_json)
    xbeam, xaxis = get_xds_coordinate_frame(integrate_hkl)

    # want to align XDS -s0 vector...
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

    R = align_reference_frame(-xbeam, dbeam, xaxis, daxis)
    xA = R * integrate_hkl_to_A_matrix(integrate_hkl)

    # assert that this should just be a simple integer rotation matrix
    # i.e. reassignment of a, b, c so...

    from scitbx import matrix

    return matrix.sqr(map(int, map(round, (dA.inverse() * xA).elems)))
Ejemplo n.º 10
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
Ejemplo n.º 11
0
  def derive_reindex_matrix(self, handle):
    '''Derive a reindexing matrix to go from the orientation matrix used
    for XDS integration to the one used for DIALS integration.'''
    from scitbx import matrix

    dA = self._experiment.crystal.get_A()
    dbeam = matrix.col(self._experiment.beam.get_direction())
    daxis = matrix.col(self._experiment.goniometer.get_rotation_axis())
    xbeam = matrix.col(handle.beam_vector).normalize()
    xaxis = matrix.col(handle.rotation_axis).normalize()

    # want to align XDS -s0 vector...
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    R = align_reference_frame(- xbeam, dbeam, xaxis, daxis)
    xA = matrix.sqr(
      handle.unit_cell_a_axis +
      handle.unit_cell_b_axis +
      handle.unit_cell_c_axis).inverse()
    xA = R * xA

    # assert that this should just be a simple integer rotation matrix
    # i.e. reassignment of a, b, c so...

    return matrix.sqr(map(int, map(round, (dA.inverse() * xA).elems)))
Ejemplo n.º 12
0
def export_xds_ascii(integrated_data,
                     experiment_list,
                     params,
                     var_model=(1, 0)):
    """Export data from integrated_data corresponding to experiment_list to
    an XDS_ASCII.HKL formatted text file."""

    from dials.array_family import flex

    # for the moment assume (and assert) that we will convert data from exactly
    # one lattice...

    assert len(experiment_list) == 1
    # select reflections that are assigned to an experiment (i.e. non-negative id)

    integrated_data = integrated_data.select(integrated_data["id"] >= 0)
    assert max(integrated_data["id"]) == 0

    # export for xds_ascii should only be for non-scaled reflections
    assert any([
        i in integrated_data
        for i in ["intensity.sum.value", "intensity.prf.value"]
    ])

    integrated_data = filter_reflection_table(
        integrated_data,
        intensity_choice=params.intensity,
        partiality_threshold=params.mtz.partiality_threshold,
        combine_partials=params.mtz.combine_partials,
        min_isigi=params.mtz.min_isigi,
        filter_ice_rings=params.mtz.filter_ice_rings,
        d_min=params.mtz.d_min,
    )

    # calculate the scl = lp/dqe correction for outputting but don't apply it as
    # it has already been applied in filter_reflection_table
    integrated_data, scl = FilteringReductionMethods.calculate_lp_qe_correction_and_filter(
        integrated_data)

    experiment = experiment_list[0]

    # sort data before output
    nref = len(integrated_data["miller_index"])
    indices = flex.size_t_range(nref)

    import copy

    unique = copy.deepcopy(integrated_data["miller_index"])
    from cctbx.miller import map_to_asu

    map_to_asu(experiment.crystal.get_space_group().type(), False, unique)

    perm = sorted(indices, key=lambda k: unique[k])
    integrated_data = integrated_data.select(flex.size_t(perm))

    from scitbx import matrix
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

    assert not experiment.goniometer is None

    unit_cell = experiment.crystal.get_unit_cell()

    from scitbx.array_family import flex

    assert not experiment.scan is None
    image_range = experiment.scan.get_image_range()
    phi_start, phi_range = experiment.scan.get_image_oscillation(
        image_range[0])

    # gather the required information for the reflection file

    nref = len(integrated_data["miller_index"])
    zdet = flex.double(integrated_data["xyzcal.px"].parts()[2])

    miller_index = integrated_data["miller_index"]

    # profile correlation
    if "profile.correlation" in integrated_data:
        prof_corr = 100.0 * integrated_data["profile.correlation"]
    else:
        prof_corr = flex.double(nref, 100.0)

    # partiality
    if "partiality" in integrated_data:
        partiality = 100 * integrated_data["partiality"]
    else:
        prof_corr = flex.double(nref, 100.0)

    if "intensity.sum.value" in integrated_data:
        I = integrated_data["intensity.sum.value"]
        V = integrated_data["intensity.sum.variance"]
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)
    else:
        I = integrated_data["intensity.prf.value"]
        V = integrated_data["intensity.prf.variance"]
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)

    fout = open(params.xds_ascii.hklout, "w")

    # first write the header - in the "standard" coordinate frame...

    panel = experiment.detector[0]
    fast = panel.get_fast_axis()
    slow = panel.get_slow_axis()
    Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
    print("Coordinate change:")
    print("%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n" %
          Rd.elems)

    fast = Rd * fast
    slow = Rd * slow

    qx, qy = panel.get_pixel_size()
    nx, ny = panel.get_image_size()
    distance = matrix.col(Rd * panel.get_origin()).dot(
        matrix.col(Rd * panel.get_normal()))
    org = Rd * (matrix.col(panel.get_origin()) -
                distance * matrix.col(panel.get_normal()))
    orgx = -org.dot(fast) / qx
    orgy = -org.dot(slow) / qy

    UB = Rd * matrix.sqr(experiment.crystal.get_A())
    real_space_ABC = UB.inverse().elems

    axis = Rd * experiment.goniometer.get_rotation_axis()
    beam = Rd * experiment.beam.get_s0()
    cell_fmt = "%9.3f %9.3f %9.3f %7.3f %7.3f %7.3f"
    axis_fmt = "%9.3f %9.3f %9.3f"

    fout.write("\n".join([
        "!FORMAT=XDS_ASCII    MERGE=FALSE    FRIEDEL'S_LAW=TRUE",
        "!Generated by dials.export",
        "!DATA_RANGE= %d %d" % image_range,
        "!ROTATION_AXIS= %9.6f %9.6f %9.6f" % axis.elems,
        "!OSCILLATION_RANGE= %f" % phi_range,
        "!STARTING_ANGLE= %f" % phi_start,
        "!STARTING_FRAME= %d" % image_range[0],
        "!SPACE_GROUP_NUMBER= %d" %
        experiment.crystal.get_space_group().type().number(),
        "!UNIT_CELL_CONSTANTS= %s" % (cell_fmt % unit_cell.parameters()),
        "!UNIT_CELL_A-AXIS= %s" % (axis_fmt % real_space_ABC[0:3]),
        "!UNIT_CELL_B-AXIS= %s" % (axis_fmt % real_space_ABC[3:6]),
        "!UNIT_CELL_C-AXIS= %s" % (axis_fmt % real_space_ABC[6:9]),
        "!X-RAY_WAVELENGTH= %f" % experiment.beam.get_wavelength(),
        "!INCIDENT_BEAM_DIRECTION= %f %f %f" % beam.elems,
        "!NX= %d NY= %d QX= %f QY= %f" % (nx, ny, qx, qy),
        "!ORGX= %9.2f ORGY= %9.2f" % (orgx, orgy),
        "!DETECTOR_DISTANCE= %8.3f" % distance,
        "!DIRECTION_OF_DETECTOR_X-AXIS= %9.5f %9.5f %9.5f" % fast.elems,
        "!DIRECTION_OF_DETECTOR_Y-AXIS= %9.5f %9.5f %9.5f" % slow.elems,
        "!VARIANCE_MODEL= %7.3e %7.3e" % var_model,
        "!NUMBER_OF_ITEMS_IN_EACH_DATA_RECORD=12",
        "!ITEM_H=1",
        "!ITEM_K=2",
        "!ITEM_L=3",
        "!ITEM_IOBS=4",
        "!ITEM_SIGMA(IOBS)=5",
        "!ITEM_XD=6",
        "!ITEM_YD=7",
        "!ITEM_ZD=8",
        "!ITEM_RLP=9",
        "!ITEM_PEAK=10",
        "!ITEM_CORR=11",
        "!ITEM_PSI=12",
        "!END_OF_HEADER",
        "",
    ]))

    # then write the data records

    s0 = Rd * matrix.col(experiment.beam.get_s0())

    for j in range(nref):
        x, y, z = integrated_data["xyzcal.px"][j]
        phi = phi_start + z * phi_range
        h, k, l = miller_index[j]
        X = (UB * (h, k, l)).rotate(axis, phi, deg=True)
        s = s0 + X
        g = s.cross(s0).normalize()
        f = (s - s0).normalize()

        # find component of beam perpendicular to f, e
        e = -(s + s0).normalize()
        if h == k and k == l:
            u = (h, -h, 0)
        else:
            u = (k - l, l - h, h - k)
        q = ((matrix.col(u).transpose() *
              UB.inverse()).normalize().transpose().rotate(axis, phi,
                                                           deg=True))

        psi = q.angle(g, deg=True)
        if q.dot(e) < 0:
            psi *= -1

        fout.write("%d %d %d %f %f %f %f %f %f %.1f %.1f %f\n" % (
            h,
            k,
            l,
            I[j],
            sigI[j],
            x,
            y,
            z,
            scl[j],
            partiality[j],
            prof_corr[j],
            psi,
        ))

    fout.write("!END_OF_DATA\n")
    fout.close()
    logger.info("Output %d reflections to %s" %
                (nref, params.xds_ascii.hklout))
Ejemplo n.º 13
0
    def get_goniometer_shadow_masker(self, goniometer=None):
        from dials.util.masking import GoniometerShadowMaskGenerator
        from scitbx.array_family import flex
        import math

        coords = flex.vec3_double(((0, 0, 0), ))

        alpha = flex.double_range(0, 190, step=10) * math.pi / 180
        r = flex.double(alpha.size(), 40)
        x = flex.double(r.size(), 107.61)
        y = -r * flex.sin(alpha)
        z = -r * flex.cos(alpha)
        coords.extend(flex.vec3_double(x, y, z))

        coords.extend(
            flex.vec3_double((
                # fixed
                (107.49, 7.84, 39.49),
                (107.39, 15.69, 38.97),
                (107.27, 23.53, 38.46),
                (107.16, 31.37, 37.94),
                (101.76, 33.99, 36.25),
                (96.37, 36.63, 34.56),
                (90.98, 39.25, 33.00),
                (85.58, 41.88, 31.18),
                (80.89, 47.06, 31.00),
                (76.55, 51.51, 31.03),
                (72.90, 55.04, 31.18),
                (66.86, 60.46, 31.67),
                (62.10, 64.41, 32.25),
            )))

        alpha = flex.double_range(180, 370, step=10) * math.pi / 180
        r = flex.double(alpha.size(), 33)
        x = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) *
             flex.cos((50 * math.pi / 180) -
                      flex.atan(r / 89.02 * flex.sin(alpha))))
        y = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) *
             flex.sin((50 * math.pi / 180) -
                      flex.atan(r / 89.02 * flex.sin(alpha))))
        z = -r * flex.cos(alpha)
        coords.extend(flex.vec3_double(x, y, z))

        coords.extend(
            flex.vec3_double((
                # fixed
                (62.10, 64.41, -32.25),
                (66.86, 60.46, -31.67),
                (72.90, 55.04, -31.18),
                (76.55, 51.51, -31.03),
                (80.89, 47.06, -31.00),
                (85.58, 41.88, -31.18),
                (90.98, 39.25, -33.00),
                (96.37, 36.63, -34.56),
                (101.76, 33.99, -36.25),
                (107.16, 31.37, -37.94),
                (107.27, 23.53, -38.46),
                (107.39, 15.69, -38.97),
                (107.49, 7.84, -39.49),
                (107.61, 0.00, -40.00))))

        # I23 end station coordinate system:
        #   X-axis: positive direction is facing away from the storage ring (from
        #           sample towards goniometer)
        #   Y-axis: positive direction is vertically up
        #   Z-axis: positive direction is in the direction of the beam (from
        #           sample towards detector)
        #   K-axis (kappa): at an angle of +50 degrees from the X-axis
        #   K & phi rotation axes: clockwise rotation is positive (right hand
        #           thumb rule)
        #   Omega-axis: along the X-axis; clockwise rotation is positive

        # End station x-axis is parallel to ImgCIF x-axis
        # End station z-axis points in opposite direction to ImgCIF definition
        # (ImgCIF: The Z-axis is derived from the source axis which goes from
        # the sample to the source)
        # Consequently end station y-axis (to complete set following right hand
        # rule) points in opposite direction to ImgCIF y-axis.
        # Kappa arm aligned with -y in ImgCIF convention

        from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
        from scitbx import matrix
        R = align_reference_frame(matrix.col((1, 0, 0)), matrix.col((1, 0, 0)),
                                  matrix.col((0, 1, 0)), matrix.col(
                                      (0, -1, 0)))
        coords = R.elems * coords

        if goniometer is None:
            goniometer = self.get_goniometer()
        return GoniometerShadowMaskGenerator(goniometer, coords,
                                             flex.size_t(len(coords), 1))
Ejemplo n.º 14
0
    def extrema_at_scan_angle(self, scan_angle):
        from scitbx.array_family import flex

        # Align end station coordinate system with ImgCIF coordinate system
        from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
        from scitbx import matrix

        R = align_reference_frame(
            matrix.col((-1, 0, 0)),
            matrix.col((1, 0, 0)),
            matrix.col((0, -1, 0)),
            matrix.col((0, 1, 0)),
        )
        faceA = R.elems * self.faceA
        faceE = R.elems * self.faceE

        axes = self.goniometer.get_axes()
        angles = self.goniometer.get_angles()
        scan_axis = self.goniometer.get_scan_axis()
        angles[scan_axis] = scan_angle

        extrema = flex.vec3_double()

        for coords in (faceA, faceE):
            coords = coords.deep_copy()
            for i, axis in enumerate(axes):
                if i == 0:
                    continue  # shadow doesn't change with phi setting
                sel = flex.bool(len(coords), True)
                rotation = matrix.col(
                    axis).axis_and_angle_as_r3_rotation_matrix(angles[i],
                                                               deg=True)
                coords.set_selected(sel, rotation.elems * coords.select(sel))
            extrema.extend(coords)

        s = matrix.col(self.faceB[0])
        mx, my, _ = self.faceB[1]
        nx, ny, _ = self.faceB[2]
        px, py, _ = self.faceB[3]

        Rchi = (R.inverse() *
                matrix.col(axes[1])).axis_and_angle_as_r3_rotation_matrix(
                    angles[1], deg=True)
        sk = Rchi * s
        sxk, syk, szk = sk.elems
        coords = flex.vec3_double((
            (sxk, syk, 0),
            (sxk, syk, szk),
            (sxk + mx / 2, syk + my / 2, szk),
            (sxk + mx, syk + my, szk),
            (sxk + (mx + nx) / 2, syk + (my + ny) / 2, szk),
            (sxk + nx, syk + ny, szk),
            (sxk + (nx + px) / 2, syk + (ny + py) / 2, szk),
            (sxk + px, syk + py, szk),
            (sxk + px, syk + py, 0),
            (sxk + px, syk + py, -szk),
            (sxk + (nx + px) / 2, syk + (ny + py) / 2, -szk),
            (sxk + nx, syk + ny, -szk),
            (sxk + (mx + nx) / 2, syk + (my + ny) / 2, -szk),
            (sxk + mx, syk + my, -szk),
            (sxk + mx / 2, syk + my / 2, -szk),
            (sxk, syk, -szk),
        ))

        coords = R.elems * coords
        Romega = matrix.col(axes[2]).axis_and_angle_as_r3_rotation_matrix(
            angles[2], deg=True)
        coords = Romega.elems * coords
        extrema.extend(coords)

        return extrema
    def extrema_at_scan_angle(self, scan_angle):
      from scitbx.array_family import flex

      # Align end station coordinate system with ImgCIF coordinate system
      from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
      from scitbx import matrix
      R = align_reference_frame(matrix.col((1,0,0)), matrix.col((-1,0,0)),
                                matrix.col((0,1,0)), matrix.col((0,1,0)))
      faceA = R.elems * self.faceA
      faceE = R.elems * self.faceE

      axes = self.goniometer.get_axes()
      angles = self.goniometer.get_angles()
      scan_axis = self.goniometer.get_scan_axis()
      angles[scan_axis] = scan_angle

      extrema = flex.vec3_double()

      for coords in (faceA, faceE):
        coords = coords.deep_copy()

        for i, axis in enumerate(axes):
          sel = flex.bool(len(coords), True)
          rotation = matrix.col(
            axis).axis_and_angle_as_r3_rotation_matrix(angles[i], deg=True)
          coords.set_selected(sel, rotation.elems * coords.select(sel))
        extrema.extend(coords)

      s = matrix.col(self.faceB[0])
      mx, my, _ = self.faceB[1]
      nx, ny, _ = self.faceB[2]
      px, py, _ = self.faceB[3]

      Rchi = (R.inverse() * matrix.col(axes[1])).axis_and_angle_as_r3_rotation_matrix(angles[1], deg=True)
      sk = Rchi * s
      sxk, syk, szk = sk.elems
      coords = flex.vec3_double((
        (sxk, syk, 0),
        (sxk, syk, szk),
        (sxk+mx/2, syk+my/2, szk),
        (sxk+mx, syk+my, szk),
        (sxk+(mx+nx)/2, syk+(my+ny)/2, szk),
        (sxk+nx, syk+ny, szk),
        (sxk+(nx+px)/2, syk+(ny+py)/2, szk),
        (sxk+px, syk+py, szk),
        (sxk+px, syk+py, 0),
        (sxk+px, syk+py, -szk),
        (sxk+(nx+px)/2, syk+(ny+py)/2, -szk),
        (sxk+nx, syk+ny, -szk),
        (sxk+(mx+nx)/2, syk+(my+ny)/2, -szk),
        (sxk+mx, syk+my, -szk),
        (sxk+mx/2, syk+my/2, -szk),
        (sxk, syk, -szk),
      ))

      coords = R.elems * coords
      Romega = matrix.col(axes[2]).axis_and_angle_as_r3_rotation_matrix(angles[2], deg=True)
      coords = Romega.elems * coords
      extrema.extend(coords)

      return extrema
Ejemplo n.º 16
0
  def __init__(self, experiment, vectors, frame='reciprocal', mode='main'):
    from libtbx.utils import Sorry
    self.experiment = experiment
    self.vectors = vectors
    self.frame = frame
    self.mode = mode

    gonio = experiment.goniometer
    scan = experiment.scan

    self.s0 = matrix.col(self.experiment.beam.get_s0())
    self.rotation_axis = matrix.col(gonio.get_rotation_axis())

    from dxtbx.model import MultiAxisGoniometer
    if not isinstance(gonio, MultiAxisGoniometer):
      raise Sorry('Only MultiAxisGoniometer models supported')
    axes = gonio.get_axes()
    if len(axes) != 3:
      raise Sorry('Only 3-axis goniometers supported')
    e1, e2, e3 = (matrix.col(e) for e in axes)

    fixed_rotation = matrix.sqr(gonio.get_fixed_rotation())
    setting_rotation = matrix.sqr(gonio.get_setting_rotation())
    rotation_axis = matrix.col(gonio.get_rotation_axis_datum())
    rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix(
      experiment.scan.get_oscillation()[0], deg=True)

    from dials.algorithms.refinement import rotation_decomposition

    results = {}

    for (v1_, v2_) in self.vectors:
      results[(v1_, v2_)] = {}
      crystal = copy.deepcopy(self.experiment.crystal)
      for smx in list(crystal.get_space_group().smx())[:]:
        cb_op = sgtbx.change_of_basis_op(smx)
        crystal = crystal.change_basis(cb_op)

        # Goniometer datum setting [D] at which the orientation was determined
        D = (setting_rotation * rotation_matrix * fixed_rotation).inverse()

        # The setting matrix [U] will vary with the datum setting according to
        # [U] = [D] [U0]
        U = crystal.get_U()

        # XXX In DIALS recorded U is equivalent to U0 - D is applied to U inside
        # prediction
        U0 = U

        B = crystal.get_B()

        if self.frame == 'direct':
          B = B.inverse().transpose()

        v1_0 = U0 * B * v1_
        v2_0 = U0 * B * v2_

        #c  (b) The laboratory frame vectors l1 & l2 are normally specified with the
        #c MODE command: MODE MAIN (the default) sets l1 (along which v1 will be
        #c placed) along the principle goniostat axis e1 (Omega), and l2 along
        #c the beam s0. This allows rotation for instance around a principle axis.
        #c The other mode is MODE CUSP, which puts l1 (v1) perpendicular to the
        #c beam (s0) and the e1 (Omega) axis, and l2 (v2) in the plane containing
        #c l1 & e1 (ie l1 = e1 x s0, l2 = e1).

        if self.mode == 'cusp':
          l1 = self.rotation_axis.cross(s0)
          l2 = self.rotation_axis
        else:
          l1 = self.rotation_axis.normalize()
          l3 = l1.cross(self.s0).normalize()
          l2 = l1.cross(l3)

        from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
        R = align_reference_frame(v1_0, l1, v2_0, l2)

        solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes(
          R, e1, e2, e3, return_both_solutions=True, deg=True)

        if solutions is None:
          continue

        results[(v1_, v2_)][smx] = solutions

    self.all_solutions = results

    self.unique_solutions = {}
    for (v1, v2), result in results.iteritems():
      for solutions in result.itervalues():
        for solution in solutions:
          k = tuple(round(a, 2) for a in solution[1:])
          self.unique_solutions.setdefault(k, set())
          self.unique_solutions[k].add((v1, v2))
Ejemplo n.º 17
0
    def extract_varying_crystal(integrate_lp, experiments):
        """Extract a varying crystal model from an INTEGRATE.LP file (static
        in blocks with step changes) and write it to the provided
        experiments
        """

        if len(experiments) > 1:
            print(
                "Can only read a varying crystal model for a single "
                + "experiment. Skipping."
            )
            return
        experiment = experiments[0]

        # read required records from the file. Relies on them being in the
        # right order as we read through once
        xds_axis = None
        xds_beam = None
        blocks, a_axis, b_axis, c_axis = [], [], [], []
        with open(integrate_lp) as f:
            for record in f:
                if record.lstrip().startswith("ROTATION_AXIS="):
                    xds_axis = record.split("ROTATION_AXIS=")[1].split()
                    break
            for record in f:
                if record.lstrip().startswith("INCIDENT_BEAM_DIRECTION="):
                    xds_beam = record.split("INCIDENT_BEAM_DIRECTION=")[1].split()
                    break
            for record in f:
                if record.lstrip().startswith("PROCESSING OF IMAGES"):
                    blocks.append(record.split("PROCESSING OF IMAGES")[1])
                    continue
                if record.lstrip().startswith("COORDINATES OF UNIT CELL A-AXIS"):
                    a_axis.append(record.split("COORDINATES OF UNIT CELL A-AXIS")[1])
                    continue
                if record.lstrip().startswith("COORDINATES OF UNIT CELL B-AXIS"):
                    b_axis.append(record.split("COORDINATES OF UNIT CELL B-AXIS")[1])
                    continue
                if record.lstrip().startswith("COORDINATES OF UNIT CELL C-AXIS"):
                    c_axis.append(record.split("COORDINATES OF UNIT CELL C-AXIS")[1])
                    continue

        # sanity checks
        msg = "INTEGRATE.LP is not in the expected format"
        nblocks = len(blocks)
        try:
            assert len(a_axis) == len(b_axis) == len(c_axis) == nblocks
            assert (xds_axis, xds_beam).count(None) == 0
        except AssertionError:
            print(msg)
            return

        # conversions to numeric
        try:
            blocks = [[int(b) for b in block.split("...")] for block in blocks]
            a_axis = [[float(a) for a in axis.split()] for axis in a_axis]
            b_axis = [[float(b) for b in axis.split()] for axis in b_axis]
            c_axis = [[float(c) for c in axis.split()] for axis in c_axis]
            xds_beam = [float(e) for e in xds_beam]
            xds_axis = [float(e) for e in xds_axis]
        except ValueError:
            print(msg)
            return

        # coordinate frame conversions
        dbeam = matrix.col(experiment.beam.get_sample_to_source_direction())
        daxis = matrix.col(experiment.goniometer.get_rotation_axis())
        xbeam = matrix.col(xds_beam).normalize()
        xaxis = matrix.col(xds_axis).normalize()

        # want to align XDS -s0 vector...
        R = align_reference_frame(-xbeam, dbeam, xaxis, daxis)

        # Make a static crystal for each block
        crystals = []
        sg = experiment.crystal.get_space_group()
        for a, b, c in zip(a_axis, b_axis, c_axis):
            a = R * matrix.col(a)
            b = R * matrix.col(b)
            c = R * matrix.col(c)
            crystals.append(Crystal(a, b, c, space_group=sg))

        # construct a list of scan points
        A_list = []
        for block, crystal in zip(blocks, crystals):
            A = crystal.get_A()
            for im in range(block[0], block[1] + 1):
                A_list.append(A)
        # Need a final scan point at the end of the final image
        A_list.append(A)

        # set the scan-varying crystal
        experiment.crystal.set_A_at_scan_points(A_list)
Ejemplo n.º 18
0
def write_par_file(file_name, experiment):
    from dxtbx.model import Crystal
    from iotbx.mtz.extract_from_symmetry_lib import ccp4_symbol
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from scitbx import matrix

    imageset = experiment.imageset
    detector = imageset.get_detector()
    goniometer = imageset.get_goniometer()
    beam = imageset.get_beam()
    scan = imageset.get_scan()

    R_to_mosflm = align_reference_frame(beam.get_s0(), (1.0, 0.0, 0.0),
                                        goniometer.get_rotation_axis(),
                                        (0.0, 0.0, 1.0))

    cryst = experiment.crystal
    cryst = cryst.change_basis(cryst.get_space_group().info().
                               change_of_basis_op_to_reference_setting())
    A = matrix.sqr(cryst.get_A())
    A_inv = A.inverse()

    real_space_a = R_to_mosflm * A_inv.elems[:3]
    real_space_b = R_to_mosflm * A_inv.elems[3:6]
    real_space_c = R_to_mosflm * A_inv.elems[6:9]

    cryst_mosflm = Crystal(real_space_a,
                           real_space_b,
                           real_space_c,
                           space_group=cryst.get_space_group())
    U_mosflm = matrix.sqr(cryst_mosflm.get_U())
    B_mosflm = matrix.sqr(cryst_mosflm.get_B())
    UB_mosflm = U_mosflm * B_mosflm
    uc_params = cryst_mosflm.get_unit_cell().parameters()
    assert U_mosflm.is_r3_rotation_matrix(), U_mosflm

    beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
    distance = detector[0].get_directed_distance()
    polarization = R_to_mosflm * matrix.col(beam.get_polarization_normal())
    rotation = matrix.col(goniometer.get_rotation_axis())
    if rotation.angle(matrix.col(
            detector[0].get_fast_axis())) < rotation.angle(
                matrix.col(detector[0].get_slow_axis())):
        direction = "FAST"
    else:
        direction = "SLOW"
    rotation = R_to_mosflm * rotation

    # Calculate average spot diameter for SEPARATION parameter
    # http://xds.mpimf-heidelberg.mpg.de/html_doc/xds_parameters.html
    # BEAM_DIVERGENCE=
    # This value is approximately arctan(spot diameter/DETECTOR_DISTANCE)
    profile = experiment.profile
    spot_diameter = math.tan(profile.delta_b() * math.pi / 180) * distance
    spot_diameter_px = spot_diameter * detector[0].get_pixel_size()[0]

    # determine parameters for RASTER keyword
    # http://www.mrc-lmb.cam.ac.uk/harry/cgi-bin/keyword2.cgi?RASTER

    # NXS, NYS (odd integers) define the overall dimensions of the rectangular array of pixels for each spot
    # NXS and NYS are set to twice the spot size plus 5 pixels
    nxs = 2 * int(math.ceil(spot_diameter_px)) + 5
    nys = nxs

    # NRX, NRY are the number of columns or rows of points in the background rim
    # NRX and NRY are set to half the spot size plus 2 pixels
    nrx = int(math.ceil(0.5 * spot_diameter_px)) + 2
    nry = nrx

    # NC the corner background cut-off which corresponds to a half-square of side NC points
    # NC is set to the mean of the spot size in X and Y plus 4
    nc = int(math.ceil(spot_diameter_px)) + 4

    def space_group_symbol(space_group):
        symbol = ccp4_symbol(space_group.info(),
                             lib_name="syminfo.lib",
                             require_at_least_one_lib=False)
        if symbol != "P 1":
            symbol = symbol.replace(" 1", "")
        symbol = symbol.replace(" ", "")
        return symbol

    logger.info("Saving BEST parameter file to %s", file_name)
    with open(file_name, "w") as f:
        print("# parameter file for BEST", file=f)
        print("TITLE          From DIALS", file=f)
        print("DETECTOR       PILA", file=f)
        print("SITE           Not set", file=f)
        print(
            "DIAMETER       %6.2f" % (max(detector[0].get_image_size()) *
                                      detector[0].get_pixel_size()[0]),
            file=f,
        )
        print(f"PIXEL          {round(detector[0].get_pixel_size()[0], 10)}",
              file=f)
        print("ROTAXIS        %4.2f %4.2f %4.2f" % rotation.elems,
              direction,
              file=f)
        print("POLAXIS        %4.2f %4.2f %4.2f" % polarization.elems, file=f)
        print("GAIN               1.00", file=f)  # correct for Pilatus images
        # http://strucbio.biologie.uni-konstanz.de/xdswiki/index.php/FAQ#You_said_that_the_XDS_deals_with_high_mosaicity._How_high_mosaicity_is_still_manageable.3F
        # http://journals.iucr.org/d/issues/2012/01/00/wd5161/index.html
        # Transform from XDS definition of sigma_m to FWHM (MOSFLM mosaicity definition)
        print(f"CMOSAIC            {experiment.profile.sigma_m() * 2.355:.2f}",
              file=f)
        print(f"PHISTART           {scan.get_oscillation_range()[0]:.2f}",
              file=f)
        print(f"PHIWIDTH           {scan.get_oscillation()[1]:.2f}", file=f)
        print(f"DISTANCE        {distance:7.2f}", file=f)
        print(f"WAVELENGTH      {beam.get_wavelength():.5f}", file=f)
        print(f"POLARISATION    {beam.get_polarization_fraction():7.5f}",
              file=f)
        print(f"SYMMETRY       {space_group_symbol(cryst.get_space_group())}",
              file=f)
        print("UB             %9.6f %9.6f %9.6f" % UB_mosflm[:3], file=f)
        print("               %9.6f %9.6f %9.6f" % UB_mosflm[3:6], file=f)
        print("               %9.6f %9.6f %9.6f" % UB_mosflm[6:], file=f)
        print("CELL           %8.2f %8.2f %8.2f %6.2f %6.2f %6.2f" % uc_params,
              file=f)
        print("RASTER           %i %i %i %i %i" % (nxs, nys, nc, nrx, nry),
              file=f)
        print(f"SEPARATION      {spot_diameter:.3f}  {spot_diameter:.3f}",
              file=f)
        print("BEAM           %8.3f %8.3f" % beam_centre, file=f)
        print("# end of parameter file for BEST", file=f)
Ejemplo n.º 19
0
def write_par_file(file_name, experiment):
    from scitbx import matrix
    from dxtbx.model.crystal import crystal_model
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from dials.command_line.refine_bravais_settings import short_space_group_name

    imageset = experiment.imageset
    detector = imageset.get_detector()
    goniometer = imageset.get_goniometer()
    beam = imageset.get_beam()
    scan = imageset.get_scan()

    R_to_mosflm = align_reference_frame(beam.get_s0(), (1.0, 0.0, 0.0),
                                        goniometer.get_rotation_axis(),
                                        (0.0, 0.0, 1.0))

    cryst = experiment.crystal
    cryst = cryst.change_basis(
      cryst.get_space_group().info()\
        .change_of_basis_op_to_reference_setting())
    A = cryst.get_A()
    A_inv = A.inverse()

    real_space_a = R_to_mosflm * A_inv.elems[:3]
    real_space_b = R_to_mosflm * A_inv.elems[3:6]
    real_space_c = R_to_mosflm * A_inv.elems[6:9]

    cryst_mosflm = crystal_model(real_space_a,
                                 real_space_b,
                                 real_space_c,
                                 space_group=cryst.get_space_group(),
                                 mosaicity=cryst.get_mosaicity())
    A_mosflm = cryst_mosflm.get_A()
    U_mosflm = cryst_mosflm.get_U()
    B_mosflm = cryst_mosflm.get_B()
    UB_mosflm = U_mosflm * B_mosflm
    uc_params = cryst_mosflm.get_unit_cell().parameters()
    assert U_mosflm.is_r3_rotation_matrix(), U_mosflm

    symmetry = cryst_mosflm.get_space_group().type().number()
    beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
    distance = detector[0].get_directed_distance()
    polarization = R_to_mosflm * matrix.col(beam.get_polarization_normal())
    rotation = matrix.col(goniometer.get_rotation_axis())
    if (rotation.angle(matrix.col(detector[0].get_fast_axis())) <
            rotation.angle(matrix.col(detector[0].get_slow_axis()))):
        direction = 'FAST'
    else:
        direction = 'SLOW'
    rotation = R_to_mosflm * rotation

    with open(file_name, 'wb') as f:  #
        print >> f, '# parameter file for BEST'
        print >> f, 'TITLE          From DIALS'
        print >> f, 'DETECTOR       PILA'
        print >> f, 'SITE           Not set'
        print >> f, 'DIAMETER       %6.2f' % (max(
            detector[0].get_image_size()) * detector[0].get_pixel_size()[0])
        print >> f, 'PIXEL          %s' % detector[0].get_pixel_size()[0]
        print >> f, 'ROTAXIS        %4.2f %4.2f %4.2f' % rotation.elems, direction
        print >> f, 'POLAXIS        %4.2f %4.2f %4.2f' % polarization.elems
        print >> f, 'GAIN               1.00'  # correct for Pilatus images
        print >> f, 'CMOSAIC            %.2f' % experiment.profile.sigma_m()
        print >> f, 'PHISTART           %.2f' % scan.get_oscillation_range()[0]
        print >> f, 'PHIWIDTH           %.2f' % scan.get_oscillation()[1]
        print >> f, 'DISTANCE        %7.2f' % distance
        print >> f, 'WAVELENGTH      %.5f' % beam.get_wavelength()
        print >> f, 'POLARISATION    %7.5f' % beam.get_polarization_fraction()
        print >> f, 'SYMMETRY       %s' % short_space_group_name(
            cryst.get_space_group())
        print >> f, 'UB             %9.2f %9.2f %9.2f' % UB_mosflm[:3]
        print >> f, '               %9.2f %9.2f %9.2f' % UB_mosflm[3:6]
        print >> f, '               %9.2f %9.2f %9.2f' % UB_mosflm[6:]
        print >> f, 'CELL           %8.2f %8.2f %8.2f %6.2f %6.2f %6.2f' % uc_params
        print >> f, 'RASTER           13  13   7   3   4'
        print >> f, 'SEPARATION      2.960  2.960'
        print >> f, 'BEAM           %8.3f %8.3f' % beam_centre
        print >> f, '# end of parameter file for BEST'
Ejemplo n.º 20
0
  def __init__(self, sweep):
    self._sweep = sweep

    # detector dimensions in pixels
    self.detector_size = map(
      int,
      (max(panel.get_raw_image_offset()[0]+panel.get_image_size()[0]
           for panel in self.get_detector()),
       max(panel.get_raw_image_offset()[1]+panel.get_image_size()[1]
           for panel in self.get_detector())))
    self.fast, self.slow = self.detector_size

    if len(self.get_detector()) > 1:
      fast = self.get_detector()[0].get_parent_fast_axis()
      slow = self.get_detector()[0].get_parent_slow_axis()
      Rd = align_reference_frame(fast, (1,0,0), slow, (0,1,0))
      origin = Rd * matrix.col(self.get_detector()[0].get_parent_origin())
    else:
      fast = self.get_detector()[0].get_fast_axis()
      slow = self.get_detector()[0].get_slow_axis()
      Rd = align_reference_frame(fast, (1,0,0), slow, (0,1,0))
      origin = Rd * matrix.col(self.get_detector()[0].get_origin())

    self.detector_x_axis = (Rd * matrix.col(fast)).elems
    self.detector_y_axis = (Rd * matrix.col(slow)).elems

    F = Rd * matrix.col(fast)
    S = Rd * matrix.col(slow)
    N = F.cross(S)
    self.detector_normal = N.elems

    self.pixel_size = self.get_detector()[0].get_pixel_size() # assume all panels same pixel size

    centre = -(origin - origin.dot(N) * N)
    x = centre.dot(F)
    y = centre.dot(S)

    f, s = self.pixel_size
    self.detector_distance = origin.dot(N)
    # Need to add 0.5 because XDS seems to do centroids in fortran coords
    self.detector_origin = (x/f + 0.5, y/f + 0.5)

    self.imagecif_to_xds_transformation_matrix = Rd

    self.panel_limits = []
    self.panel_x_axis = []
    self.panel_y_axis = []
    self.panel_origin = []
    self.panel_distance = []
    self.panel_normal = []

    for panel_id, panel in enumerate(self.get_detector()):

      f = Rd * matrix.col(panel.get_fast_axis())
      s = Rd * matrix.col(panel.get_slow_axis())
      n = f.cross(s)

      xmin, ymin = panel.get_raw_image_offset()
      xmax = xmin + panel.get_image_size()[0]
      ymax = ymin + panel.get_image_size()[1]
      self.panel_limits.append((xmin+1, xmax, ymin+1, ymax))

      o = Rd * matrix.col(panel.get_origin())
      op = o.dot(n) * n
      d0 = matrix.col((-x, -y, self.detector_distance))
      orgsx = (op - o + d0).dot(f) / self.pixel_size[0] + xmin
      orgsy = (op - o + d0).dot(s) / self.pixel_size[1] + ymin
      panel_distance = op.dot(n) - d0.dot(n)

      # axes in local (i.e. detector) frame
      fl = matrix.col(panel.get_local_fast_axis())
      sl = matrix.col(panel.get_local_slow_axis())
      nl = fl.cross(sl)

      self.panel_x_axis.append(fl.elems)
      self.panel_y_axis.append(sl.elems)
      self.panel_normal.append(nl.elems)
      self.panel_origin.append((orgsx, orgsy))
      self.panel_distance.append(panel_distance)

    # Beam stuff
    self.wavelength = self.get_beam().get_wavelength()
    self.beam_vector = Rd * matrix.col(self.get_beam().get_direction())
    # just to make sure it is the correct length
    self.beam_vector = self.beam_vector.normalize() #/ self.wavelength
    self.beam_vector = (- self.beam_vector).elems

    # Scan and goniometer stuff
    self.starting_frame = self.get_scan().get_image_range()[0]
    self.starting_angle = self.get_scan().get_oscillation()[0]
    self.oscillation_range = self.get_scan().get_oscillation()[1]
    self.rotation_axis = (
        Rd * matrix.col(self.get_goniometer().get_rotation_axis())).elems
    return
Ejemplo n.º 21
0
def _export_experiment(filename,
                       integrated_data,
                       experiment,
                       params,
                       var_model=(1, 0)):
    # type: (str, flex.reflection_table, dxtbx.model.Experiment, libtbx.phil.scope_extract, Tuple)
    """Export a single experiment to an XDS_ASCII.HKL format file.

    Args:
        filename: The file to write to
        integrated_data: The reflection table, pre-selected to one experiment
        experiment: The experiment list entry to export
        params: The PHIL configuration object
        var_model:
    """
    # export for xds_ascii should only be for non-scaled reflections
    assert any(i in integrated_data
               for i in ["intensity.sum.value", "intensity.prf.value"])
    # Handle requesting profile intensities (default via auto) but no column
    if "profile" in params.intensity and "intensity.prf.value" not in integrated_data:
        raise Sorry(
            "Requested profile intensity data but only summed present. Use intensity=sum."
        )

    integrated_data = filter_reflection_table(
        integrated_data,
        intensity_choice=params.intensity,
        partiality_threshold=params.mtz.partiality_threshold,
        combine_partials=params.mtz.combine_partials,
        min_isigi=params.mtz.min_isigi,
        filter_ice_rings=params.mtz.filter_ice_rings,
        d_min=params.mtz.d_min,
    )

    # calculate the scl = lp/dqe correction for outputting but don't apply it as
    # it has already been applied in filter_reflection_table
    (
        integrated_data,
        scl,
    ) = FilteringReductionMethods.calculate_lp_qe_correction_and_filter(
        integrated_data)

    # sort data before output
    nref = len(integrated_data["miller_index"])
    indices = flex.size_t_range(nref)

    unique = copy.deepcopy(integrated_data["miller_index"])

    map_to_asu(experiment.crystal.get_space_group().type(), False, unique)

    perm = sorted(indices, key=lambda k: unique[k])
    integrated_data = integrated_data.select(flex.size_t(perm))

    if experiment.goniometer is None:
        print(
            "Warning: No goniometer. Experimentally exporting with (1 0 0) axis"
        )

    unit_cell = experiment.crystal.get_unit_cell()

    if experiment.scan is None:
        print(
            "Warning: No Scan. Experimentally exporting no-oscillation values")
        image_range = (1, 1)
        phi_start, phi_range = 0.0, 0.0
    else:
        image_range = experiment.scan.get_image_range()
        phi_start, phi_range = experiment.scan.get_image_oscillation(
            image_range[0])

    # gather the required information for the reflection file

    nref = len(integrated_data["miller_index"])

    miller_index = integrated_data["miller_index"]

    # profile correlation
    if "profile.correlation" in integrated_data:
        prof_corr = 100.0 * integrated_data["profile.correlation"]
    else:
        prof_corr = flex.double(nref, 100.0)

    # partiality
    if "partiality" in integrated_data:
        partiality = 100 * integrated_data["partiality"]
    else:
        prof_corr = flex.double(nref, 100.0)

    if "intensity.sum.value" in integrated_data:
        I = integrated_data["intensity.sum.value"]
        V = integrated_data["intensity.sum.variance"]
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)
    else:
        I = integrated_data["intensity.prf.value"]
        V = integrated_data["intensity.prf.variance"]
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)

    fout = open(filename, "w")

    # first write the header - in the "standard" coordinate frame...

    panel = experiment.detector[0]
    fast = panel.get_fast_axis()
    slow = panel.get_slow_axis()
    Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
    print("Coordinate change:")
    print("%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n" %
          Rd.elems)

    fast = Rd * fast
    slow = Rd * slow

    qx, qy = panel.get_pixel_size()
    nx, ny = panel.get_image_size()
    distance = matrix.col(Rd * panel.get_origin()).dot(
        matrix.col(Rd * panel.get_normal()))
    org = Rd * (matrix.col(panel.get_origin()) -
                distance * matrix.col(panel.get_normal()))
    orgx = -org.dot(fast) / qx
    orgy = -org.dot(slow) / qy

    UB = Rd * matrix.sqr(experiment.crystal.get_A())
    real_space_ABC = UB.inverse().elems

    if experiment.goniometer is not None:
        axis = Rd * experiment.goniometer.get_rotation_axis()
    else:
        axis = Rd * (1, 0, 0)

    beam = Rd * experiment.beam.get_s0()
    cell_fmt = "%9.3f %9.3f %9.3f %7.3f %7.3f %7.3f"
    axis_fmt = "%9.3f %9.3f %9.3f"

    fout.write("\n".join([
        "!FORMAT=XDS_ASCII    MERGE=FALSE    FRIEDEL'S_LAW=TRUE",
        "!Generated by dials.export",
        "!DATA_RANGE= %d %d" % image_range,
        "!ROTATION_AXIS= %9.6f %9.6f %9.6f" % axis.elems,
        "!OSCILLATION_RANGE= %f" % phi_range,
        "!STARTING_ANGLE= %f" % phi_start,
        "!STARTING_FRAME= %d" % image_range[0],
        "!SPACE_GROUP_NUMBER= %d" %
        experiment.crystal.get_space_group().type().number(),
        "!UNIT_CELL_CONSTANTS= %s" % (cell_fmt % unit_cell.parameters()),
        "!UNIT_CELL_A-AXIS= %s" % (axis_fmt % real_space_ABC[0:3]),
        "!UNIT_CELL_B-AXIS= %s" % (axis_fmt % real_space_ABC[3:6]),
        "!UNIT_CELL_C-AXIS= %s" % (axis_fmt % real_space_ABC[6:9]),
        "!X-RAY_WAVELENGTH= %f" % experiment.beam.get_wavelength(),
        "!INCIDENT_BEAM_DIRECTION= %f %f %f" % beam.elems,
        "!NX= %d NY= %d QX= %f QY= %f" % (nx, ny, qx, qy),
        "!ORGX= %9.2f ORGY= %9.2f" % (orgx, orgy),
        "!DETECTOR_DISTANCE= %8.3f" % distance,
        "!DIRECTION_OF_DETECTOR_X-AXIS= %9.5f %9.5f %9.5f" % fast.elems,
        "!DIRECTION_OF_DETECTOR_Y-AXIS= %9.5f %9.5f %9.5f" % slow.elems,
        "!VARIANCE_MODEL= %7.3e %7.3e" % var_model,
        "!NUMBER_OF_ITEMS_IN_EACH_DATA_RECORD=12",
        "!ITEM_H=1",
        "!ITEM_K=2",
        "!ITEM_L=3",
        "!ITEM_IOBS=4",
        "!ITEM_SIGMA(IOBS)=5",
        "!ITEM_XD=6",
        "!ITEM_YD=7",
        "!ITEM_ZD=8",
        "!ITEM_RLP=9",
        "!ITEM_PEAK=10",
        "!ITEM_CORR=11",
        "!ITEM_PSI=12",
        "!END_OF_HEADER",
        "",
    ]))

    # then write the data records

    s0 = Rd * matrix.col(experiment.beam.get_s0())

    for j in range(nref):
        x, y, z = integrated_data["xyzcal.px"][j]
        phi = phi_start + z * phi_range
        h, k, l = miller_index[j]
        X = (UB * (h, k, l)).rotate(axis, phi, deg=True)
        s = s0 + X
        g = s.cross(s0).normalize()

        # find component of beam perpendicular to f, e
        e = -(s + s0).normalize()
        if h == k and k == l:
            u = (h, -h, 0)
        else:
            u = (k - l, l - h, h - k)
        q = ((matrix.col(u).transpose() *
              UB.inverse()).normalize().transpose().rotate(axis, phi,
                                                           deg=True))

        psi = q.angle(g, deg=True)
        if q.dot(e) < 0:
            psi *= -1

        fout.write("%d %d %d %f %f %f %f %f %f %.1f %.1f %f\n" % (
            h,
            k,
            l,
            I[j],
            sigI[j],
            x,
            y,
            z,
            scl[j],
            partiality[j],
            prof_corr[j],
            psi,
        ))

    fout.write("!END_OF_DATA\n")
    fout.close()
    logger.info("Output %d reflections to %s" % (nref, filename))
Ejemplo n.º 22
0
def run(args):

  from dials.util.options import OptionParser
  from dials.util.options import flatten_experiments
  from libtbx.utils import Sorry
  import libtbx.load_env

  usage = "%s [options] experiments.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 = flatten_experiments(params.input.experiments)
  if len(experiments) <= 1:
    parser.print_help()
    return

  from dials.algorithms.indexing.compare_orientation_matrices import \
       difference_rotation_matrix_axis_angle
  from scitbx import matrix
  crystals = []
  for experiment in experiments:
    crystal = experiment.crystal
    gonio = experiment.goniometer
    assert len(experiments) == (len(gonio.get_axes())+1)
    scan = experiment.scan
    fixed_rotation = matrix.sqr(gonio.get_fixed_rotation())
    setting_rotation = matrix.sqr(gonio.get_setting_rotation())
    rotation_axis = matrix.col(gonio.get_rotation_axis_datum())
    rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix(
      scan.get_oscillation()[0], deg=True)
    U = matrix.sqr(crystal.get_U())
    U = setting_rotation * rotation_matrix * fixed_rotation * U
    crystal.set_U(U)
    if params.space_group is not None:
      crystal.set_space_group(params.space_group.group())

  rows = []

  from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
  from scitbx import matrix
  R_to_mosflm = align_reference_frame(
    experiments[0].beam.get_s0(), (1.0, 0.0, 0.0),
    experiments[0].goniometer.get_rotation_axis(), (0.0, 0.0, 1.0))

  axes = []
  angles = []

  for i in range(len(experiments) - 1):
    target_angle = experiments[i+1].goniometer.get_angles()[i]
    R_ij, axis, angle, cb_op = difference_rotation_matrix_axis_angle(
      experiments[i].crystal, experiments[i+1].crystal, target_angle=target_angle)
    gonio = experiments[i+1].goniometer
    axis_names = gonio.get_names()
    axes.append(axis)
    angles.append(angle)
    depends_on = '.'
    if i+1 < len(axis_names):
      depends_on = axis_names[i+1]
    rows.insert(0, (
      axis_names[i], 'rotation', 'goniometer', depends_on,
      '%.4f' %axis[0], '%.4f' %axis[1], '%.4f' %axis[2], '.', '.', '.'))

  axis_names = experiments[0].goniometer.get_names()
  print "Goniometer axes and angles (ImgCIF coordinate system):"
  for axis, angle, name in zip(axes, angles, axis_names):
    print "%s: " %name, "rotation of %.3f degrees" %angle, "about axis (%.5f, %.5f, %.5f)" %axis

  print
  print "Goniometer axes and angles (MOSFLM coordinate system):"
  for axis, angle, name in zip(axes, angles, axis_names):
    print "%s: " %name, "rotation of %.3f degrees" %angle, "about axis (%.5f, %.5f, %.5f)" %(
      R_to_mosflm * matrix.col(axis)).elems

  print
  print "ImgCIF _axis loop template:"
  from iotbx import cif
  loop = cif.model.loop(
    header=['_axis.id', '_axis.type', '_axis.equipment', '_axis.depends_on',
            '_axis.vector[1]', '_axis.vector[2]', '_axis.vector[3]',
            '_axis.offset[1]', '_axis.offset[2]', '_axis.offset[3]'])
  for row in reversed(rows):
    loop.add_row(row)

  print loop

  if params.output.xoalign is not None:
    write_xoalign_config(params.output.xoalign, axes, axis_names)
Ejemplo n.º 23
0
  def extract_varying_crystal(integrate_lp, experiments):
    '''Extract a varying crystal model from an INTEGRATE.LP file (static
    in blocks with step changes) and write it to the provided
    experiments
    '''

    if len(experiments) > 1:
      print "Can only read a varying crystal model for a single " +\
            "experiment. Skipping."
      return
    experiment = experiments[0]

    # read required records from the file. Relies on them being in the
    # right order as we read through once
    xds_axis = None
    xds_beam = None
    blocks, a_axis, b_axis, c_axis = [], [], [], []
    with open(integrate_lp) as f:
      for record in f:
        if record.lstrip().startswith("ROTATION_AXIS="):
          xds_axis = record.split("ROTATION_AXIS=")[1].split()
          break
      for record in f:
        if record.lstrip().startswith("INCIDENT_BEAM_DIRECTION="):
          xds_beam = record.split("INCIDENT_BEAM_DIRECTION=")[1].split()
          break
      for record in f:
        if record.lstrip().startswith("PROCESSING OF IMAGES"):
          blocks.append(record.split("PROCESSING OF IMAGES")[1])
          continue
        if record.lstrip().startswith("COORDINATES OF UNIT CELL A-AXIS"):
          a_axis.append(record.split("COORDINATES OF UNIT CELL A-AXIS")[1])
          continue
        if record.lstrip().startswith("COORDINATES OF UNIT CELL B-AXIS"):
          b_axis.append(record.split("COORDINATES OF UNIT CELL B-AXIS")[1])
          continue
        if record.lstrip().startswith("COORDINATES OF UNIT CELL C-AXIS"):
          c_axis.append(record.split("COORDINATES OF UNIT CELL C-AXIS")[1])
          continue

    # sanity checks
    msg = "INTEGRATE.LP is not in the expected format"
    nblocks = len(blocks)
    try:
      assert len(a_axis) == len(b_axis) == len(c_axis) == nblocks
      assert (xds_axis, xds_beam).count(None) == 0
    except AssertionError:
      print msg
      return

    # conversions to numeric
    try:
      blocks = [map(int, block.split("...")) for block in blocks]
      a_axis = [map(float, axis.split()) for axis in a_axis]
      b_axis = [map(float, axis.split()) for axis in b_axis]
      c_axis = [map(float, axis.split()) for axis in c_axis]
      xds_beam = [float(e) for e in xds_beam]
      xds_axis = [float(e) for e in xds_axis]
    except ValueError:
      print msg
      return

    # coordinate frame conversions
    from scitbx import matrix
    dbeam = matrix.col(experiment.beam.get_direction())
    daxis = matrix.col(experiment.goniometer.get_rotation_axis())
    xbeam = matrix.col(xds_beam).normalize()
    xaxis = matrix.col(xds_axis).normalize()

    # want to align XDS -s0 vector...
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    R = align_reference_frame(- xbeam, dbeam, xaxis, daxis)

    # Make a static crystal for each block
    from dxtbx.model.crystal import crystal_model
    crystals = []
    sg = experiment.crystal.get_space_group()
    for a, b, c in zip(a_axis, b_axis, c_axis):
      a = R * matrix.col(a)
      b = R * matrix.col(b)
      c = R * matrix.col(c)
      crystals.append(crystal_model(a, b, c, space_group=sg))

    # construct a list of scan points
    A_list = []
    for block, crystal in zip(blocks, crystals):
      A = crystal.get_A()
      for im in range(block[0], block[1] + 1):
        A_list.append(A)
    # Need a final scan point at the end of the final image
    A_list.append(A)

    # set the scan-varying crystal
    experiment.crystal.set_A_at_scan_points(A_list)

    return
Ejemplo n.º 24
0
def run(args):

    from dials.util.options import OptionParser
    from dials.util.options import flatten_experiments
    from dials.util.options import flatten_reflections
    import libtbx.load_env

    usage = "%s [options] datablock.json" % (libtbx.env.dispatcher_name)

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

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

    if len(reflections) == 0 or len(experiments) == 0:
        parser.print_help()
        exit(0)

    reflections = reflections[0]
    assert len(experiments) == 1

    experiment = experiments[0]

    from dials.command_line.check_strategy import filter_shadowed_reflections

    sel = filter_shadowed_reflections(experiments, reflections)
    print(
        "%i/%i (%.2f%%) shadowed reflections"
        % (sel.count(True), sel.size(), 100 * sel.count(True) / sel.size())
    )

    if params.negate:
        sel = ~sel
    shadowed = reflections.select(sel)
    shadowed.as_pickle(params.output.reflections)

    if params.output.filter_hkl is not None:

        from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
        from scitbx import matrix

        detector = experiment.detector

        if len(detector) > 1:
            fast = detector[0].get_parent_fast_axis()
            slow = detector[0].get_parent_slow_axis()
            Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
            origin = Rd * matrix.col(detector[0].get_parent_origin())
        else:
            fast = detector[0].get_fast_axis()
            slow = detector[0].get_slow_axis()
            Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
            origin = Rd * matrix.col(detector[0].get_origin())

        with open(params.output.filter_hkl, "wb") as f:

            for ref in shadowed:
                p = detector[ref["panel"]]
                ox, oy = p.get_raw_image_offset()
                h, k, l = ref["miller_index"]
                x, y, z = ref["xyzcal.px"]
                dx, dy, dz = (2, 2, 2)
                print(
                    "%i %i %i %.1f %.1f %.1f %.1f %.1f %.1f"
                    % (h, k, l, x + ox, y + oy, z, dx, dy, dz),
                    file=f,
                )
Ejemplo n.º 25
0
def export_xds_ascii(integrated_data, experiment_list, hklout, summation=False,
                     include_partials=False, keep_partials=False, var_model=(1,0)):
  '''Export data from integrated_data corresponding to experiment_list to
  an XDS_ASCII.HKL formatted text file.'''

  from dials.array_family import flex
  import math

  # for the moment assume (and assert) that we will convert data from exactly
  # one lattice...

  assert(len(experiment_list) == 1)
  # select reflections that are assigned to an experiment (i.e. non-negative id)

  integrated_data = integrated_data.select(integrated_data['id'] >= 0)
  assert max(integrated_data['id']) == 0

  if not summation:
    assert('intensity.prf.value' in integrated_data)

  if 'intensity.prf.variance' in integrated_data:
    selection = integrated_data.get_flags(
      integrated_data.flags.integrated,
      all=True)
  else:
    selection = integrated_data.get_flags(
      integrated_data.flags.integrated_sum)
  integrated_data = integrated_data.select(selection)

  selection = integrated_data['intensity.sum.variance'] <= 0
  if selection.count(True) > 0:
    integrated_data.del_selected(selection)
    logger.info('Removing %d reflections with negative variance' % \
          selection.count(True))

  if 'intensity.prf.variance' in integrated_data:
    selection = integrated_data['intensity.prf.variance'] <= 0
    if selection.count(True) > 0:
      integrated_data.del_selected(selection)
      logger.info('Removing %d profile reflections with negative variance' % \
            selection.count(True))

  if include_partials:
    integrated_data = sum_partial_reflections(integrated_data)
    integrated_data = scale_partial_reflections(integrated_data)

  if 'partiality' in integrated_data:
    selection = integrated_data['partiality'] < 0.99
    if selection.count(True) > 0 and not keep_partials:
      integrated_data.del_selected(selection)
      logger.info('Removing %d incomplete reflections' % \
        selection.count(True))

  experiment = experiment_list[0]

  # sort data before output
  nref = len(integrated_data['miller_index'])
  indices = flex.size_t_range(nref)

  import copy
  unique = copy.deepcopy(integrated_data['miller_index'])
  from cctbx.miller import map_to_asu
  map_to_asu(experiment.crystal.get_space_group().type(), False, unique)

  perm = sorted(indices, key=lambda k: unique[k])
  integrated_data = integrated_data.select(flex.size_t(perm))

  from scitbx import matrix
  from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

  assert (not experiment.goniometer is None)

  unit_cell = experiment.crystal.get_unit_cell()

  from scitbx.array_family import flex
  from math import floor, sqrt

  assert(not experiment.scan is None)
  image_range = experiment.scan.get_image_range()
  phi_start, phi_range = experiment.scan.get_image_oscillation(image_range[0])

  # gather the required information for the reflection file

  nref = len(integrated_data['miller_index'])
  zdet = flex.double(integrated_data['xyzcal.px'].parts()[2])

  miller_index = integrated_data['miller_index']

  I = None
  sigI = None

  # export including scale factors

  if 'lp' in integrated_data:
    lp = integrated_data['lp']
  else:
    lp = flex.double(nref, 1.0)
  if 'dqe' in integrated_data:
    dqe = integrated_data['dqe']
  else:
    dqe = flex.double(nref, 1.0)
  scl = lp / dqe

  # profile correlation
  if 'profile.correlation' in integrated_data:
    prof_corr = 100.0 * integrated_data['profile.correlation']
  else:
    prof_corr = flex.double(nref, 100.0)

  # partiality
  if 'partiality' in integrated_data:
    partiality = 100 * integrated_data['partiality']
  else:
    prof_corr = flex.double(nref, 100.0)

  if summation:
    I = integrated_data['intensity.sum.value'] * scl
    V = integrated_data['intensity.sum.variance'] * scl * scl
    assert V.all_gt(0)
    V = var_model[0] * (V + var_model[1] * I * I)
    sigI = flex.sqrt(V)
  else:
    I = integrated_data['intensity.prf.value'] * scl
    V = integrated_data['intensity.prf.variance'] * scl * scl
    assert V.all_gt(0)
    V = var_model[0] * (V + var_model[1] * I * I)
    sigI = flex.sqrt(V)

  fout = open(hklout, 'w')

  # first write the header - in the "standard" coordinate frame...

  panel = experiment.detector[0]
  fast = panel.get_fast_axis()
  slow = panel.get_slow_axis()
  Rd = align_reference_frame(fast, (1,0,0), slow, (0,1,0))
  print 'Coordinate change:'
  print '%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n' % Rd.elems

  fast = Rd * fast
  slow = Rd * slow

  qx, qy = panel.get_pixel_size()
  nx, ny = panel.get_image_size()
  distance = matrix.col(Rd * panel.get_origin()).dot(
      matrix.col(Rd * panel.get_normal()))
  org = Rd * (matrix.col(panel.get_origin()) - distance * matrix.col(
      panel.get_normal()))
  orgx = - org.dot(fast) / qx
  orgy = - org.dot(slow) / qy

  UB = Rd * matrix.sqr(experiment.crystal.get_A())
  real_space_ABC = UB.inverse().elems

  axis = Rd * experiment.goniometer.get_rotation_axis()
  beam = Rd * experiment.beam.get_s0()
  cell_fmt = '%9.3f %9.3f %9.3f %7.3f %7.3f %7.3f'
  axis_fmt = '%9.3f %9.3f %9.3f'

  fout.write('\n'.join([
    '!FORMAT=XDS_ASCII    MERGE=FALSE    FRIEDEL\'S_LAW=TRUE',
    '!Generated by dials.export',
    '!DATA_RANGE= %d %d' % image_range,
    '!ROTATION_AXIS= %9.6f %9.6f %9.6f' % axis.elems,
    '!OSCILLATION_RANGE= %f' % phi_range,
    '!STARTING_ANGLE= %f' % phi_start,
    '!STARTING_FRAME= %d' % image_range[0],
    '!SPACE_GROUP_NUMBER= %d' % experiment.crystal.get_space_group().type().number(),
    '!UNIT_CELL_CONSTANTS= %s' % (cell_fmt % unit_cell.parameters()),
    '!UNIT_CELL_A-AXIS= %s' % (axis_fmt % real_space_ABC[0:3]),
    '!UNIT_CELL_B-AXIS= %s' % (axis_fmt % real_space_ABC[3:6]),
    '!UNIT_CELL_C-AXIS= %s' % (axis_fmt % real_space_ABC[6:9]),
    '!X-RAY_WAVELENGTH= %f' % experiment.beam.get_wavelength(),
    '!INCIDENT_BEAM_DIRECTION= %f %f %f' % beam.elems,
    '!NX= %d NY= %d QX= %f QY= %f' % (nx, ny, qx, qy),
    '!ORGX= %9.2f ORGY= %9.2f' % (orgx, orgy),
    '!DETECTOR_DISTANCE= %8.3f' % distance,
    '!DIRECTION_OF_DETECTOR_X-AXIS= %9.5f %9.5f %9.5f' % fast.elems,
    '!DIRECTION_OF_DETECTOR_Y-AXIS= %9.5f %9.5f %9.5f' % slow.elems,
    '!VARIANCE_MODEL= %7.3e %7.3e' % var_model,
    '!NUMBER_OF_ITEMS_IN_EACH_DATA_RECORD=12',
    '!ITEM_H=1',
    '!ITEM_K=2',
    '!ITEM_L=3',
    '!ITEM_IOBS=4',
    '!ITEM_SIGMA(IOBS)=5',
    '!ITEM_XD=6',
    '!ITEM_YD=7',
    '!ITEM_ZD=8',
    '!ITEM_RLP=9',
    '!ITEM_PEAK=10',
    '!ITEM_CORR=11',
    '!ITEM_PSI=12',
    '!END_OF_HEADER',
    '']))

  # then write the data records

  s0 = Rd * matrix.col(experiment.beam.get_s0())

  for j in range(nref):
    x, y, z = integrated_data['xyzcal.px'][j]
    phi = phi_start + z * phi_range
    h, k, l = miller_index[j]
    X = (UB * (h, k, l)).rotate(axis, phi, deg=True)
    s = s0 + X
    g = s.cross(s0).normalize()
    f = (s - s0).normalize()

    # find component of beam perpendicular to f, e
    e = - (s + s0).normalize()
    if h == k and k == l:
      u = (h, -h, 0)
    else:
      u = (k - l, l - h, h - k)
    q = (matrix.col(u).transpose() * UB.inverse()).normalize(
        ).transpose().rotate(axis, phi, deg=True)

    psi = q.angle(g, deg=True)
    if q.dot(e) < 0:
      psi *= -1

    fout.write('%d %d %d %f %f %f %f %f %f %.1f %.1f %f\n' %
               (h, k, l, I[j], sigI[j], x, y, z, scl[j], partiality[j], prof_corr[j], psi))

  fout.write('!END_OF_DATA\n')
  fout.close()
  logger.info('Output %d reflections to %s' % (nref, hklout))
  return
Ejemplo n.º 26
0
def dump(experiments, directory):
    """
    Dump the experiments in mosflm format

    :param experiments: The experiments to dump
    :param directory: The directory to write to
    """
    for i, experiment in enumerate(experiments):
        suffix = ""
        if len(experiments) > 1:
            suffix = "_%i" % (i + 1)

        sub_dir = "%s%s" % (directory, suffix)
        if not os.path.isdir(sub_dir):
            os.makedirs(sub_dir)
        detector = experiment.detector
        beam = experiment.beam
        goniometer = experiment.goniometer

        # XXX imageset is getting the experimental geometry from the image files
        # rather than the input models.expt file
        imageset = experiment.imageset

        R_to_mosflm = align_reference_frame(
            beam.get_s0(),
            (1.0, 0.0, 0.0),
            goniometer.get_rotation_axis(),
            (0.0, 0.0, 1.0),
        )

        cryst = experiment.crystal
        cryst = cryst.change_basis(cryst.get_space_group().info().
                                   change_of_basis_op_to_reference_setting())
        A = matrix.sqr(cryst.get_A())
        A_inv = A.inverse()

        real_space_a = R_to_mosflm * A_inv.elems[:3]
        real_space_b = R_to_mosflm * A_inv.elems[3:6]
        real_space_c = R_to_mosflm * A_inv.elems[6:9]

        cryst_mosflm = Crystal(
            real_space_a,
            real_space_b,
            real_space_c,
            space_group=cryst.get_space_group(),
        )
        A_mosflm = matrix.sqr(cryst_mosflm.get_A())
        U_mosflm = matrix.sqr(cryst_mosflm.get_U())
        assert U_mosflm.is_r3_rotation_matrix(), U_mosflm
        w = beam.get_wavelength()

        index_mat = os.path.join(sub_dir, "index.mat")
        mosflm_in = os.path.join(sub_dir, "mosflm.in")
        print("Exporting experiment to %s and %s" % (index_mat, mosflm_in))

        with open(index_mat, "w") as f:
            f.write(
                format_mosflm_mat(w * A_mosflm, U_mosflm,
                                  cryst.get_unit_cell()))

        img_dir, template = os.path.split(imageset.get_template())
        symmetry = cryst_mosflm.get_space_group().type().number()
        beam_centre = tuple(
            reversed(detector[0].get_beam_centre(beam.get_s0())))
        distance = detector[0].get_directed_distance()

        with open(mosflm_in, "w") as f:
            f.write(
                write_mosflm_input(
                    directory=img_dir,
                    template=template,
                    symmetry=symmetry,
                    beam_centre=beam_centre,
                    distance=distance,
                    mat_file="index.mat",
                ))
Ejemplo n.º 27
0
Archivo: xds.py Proyecto: hbrunie/dxtbx
    def __init__(self, sweep):
        self._sweep = sweep

        # detector dimensions in pixels
        self.detector_size = map(
            int,
            (
                max(panel.get_raw_image_offset()[0] + panel.get_image_size()[0]
                    for panel in self.get_detector()),
                max(panel.get_raw_image_offset()[1] + panel.get_image_size()[1]
                    for panel in self.get_detector()),
            ),
        )
        self.fast, self.slow = self.detector_size

        if len(self.get_detector()) > 1:
            fast = self.get_detector()[0].get_parent_fast_axis()
            slow = self.get_detector()[0].get_parent_slow_axis()
            Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
            origin = Rd * matrix.col(
                self.get_detector()[0].get_parent_origin())
        else:
            fast = self.get_detector()[0].get_fast_axis()
            slow = self.get_detector()[0].get_slow_axis()
            Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
            origin = Rd * matrix.col(self.get_detector()[0].get_origin())

        self.detector_x_axis = (Rd * matrix.col(fast)).elems
        self.detector_y_axis = (Rd * matrix.col(slow)).elems

        F = Rd * matrix.col(fast)
        S = Rd * matrix.col(slow)
        N = F.cross(S)
        self.detector_normal = N.elems

        # assume all panels same pixel size
        self.pixel_size = self.get_detector()[0].get_pixel_size()

        centre = -(origin - origin.dot(N) * N)
        x = centre.dot(F)
        y = centre.dot(S)

        f, s = self.pixel_size
        self.detector_distance = origin.dot(N)
        # Need to add 0.5 because XDS seems to do centroids in fortran coords
        self.detector_origin = (x / f + 0.5, y / f + 0.5)

        self.imagecif_to_xds_transformation_matrix = Rd

        self.panel_limits = []
        self.panel_x_axis = []
        self.panel_y_axis = []
        self.panel_origin = []
        self.panel_distance = []
        self.panel_normal = []

        for panel_id, panel in enumerate(self.get_detector()):

            f = Rd * matrix.col(panel.get_fast_axis())
            s = Rd * matrix.col(panel.get_slow_axis())
            n = f.cross(s)

            xmin, ymin = panel.get_raw_image_offset()
            xmax = xmin + panel.get_image_size()[0]
            ymax = ymin + panel.get_image_size()[1]
            self.panel_limits.append((xmin + 1, xmax, ymin + 1, ymax))

            o = Rd * matrix.col(panel.get_origin())
            op = o.dot(n) * n
            d0 = matrix.col((-x, -y, self.detector_distance))
            orgsx = (op - o + d0).dot(f) / self.pixel_size[0] + xmin
            orgsy = (op - o + d0).dot(s) / self.pixel_size[1] + ymin
            panel_distance = op.dot(n) - d0.dot(n)

            # axes in local (i.e. detector) frame
            fl = matrix.col(panel.get_local_fast_axis())
            sl = matrix.col(panel.get_local_slow_axis())
            nl = fl.cross(sl)

            self.panel_x_axis.append(fl.elems)
            self.panel_y_axis.append(sl.elems)
            self.panel_normal.append(nl.elems)
            self.panel_origin.append((orgsx, orgsy))
            self.panel_distance.append(panel_distance)

        # Beam stuff
        self.wavelength = self.get_beam().get_wavelength()
        self.beam_vector = Rd * matrix.col(self.get_beam().get_direction())
        # just to make sure it is the correct length
        self.beam_vector = self.beam_vector.normalize()  # / self.wavelength
        self.beam_vector = (-self.beam_vector).elems

        # Scan and goniometer stuff
        self.starting_frame = self.get_scan().get_image_range()[0]
        self.starting_angle = self.get_scan().get_oscillation()[0]
        self.oscillation_range = self.get_scan().get_oscillation()[1]
        self.rotation_axis = (
            Rd * matrix.col(self.get_goniometer().get_rotation_axis())).elems
Ejemplo n.º 28
0
def run(args):

    from dials.util.options import OptionParser
    from dials.util.options import flatten_experiments
    import libtbx.load_env

    usage = "%s [options] experiments.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 = flatten_experiments(params.input.experiments)
    if len(experiments) <= 1:
        parser.print_help()
        return

    from dials.algorithms.indexing.compare_orientation_matrices import \
         difference_rotation_matrix_axis_angle
    from scitbx import matrix
    crystals = []
    for experiment in experiments:
        crystal = experiment.crystal
        gonio = experiment.goniometer
        assert len(experiments) == (len(gonio.get_axes()) + 1)
        scan = experiment.scan
        fixed_rotation = matrix.sqr(gonio.get_fixed_rotation())
        setting_rotation = matrix.sqr(gonio.get_setting_rotation())
        rotation_axis = matrix.col(gonio.get_rotation_axis_datum())
        rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix(
            scan.get_oscillation()[0], deg=True)
        U = matrix.sqr(crystal.get_U())
        U = setting_rotation * rotation_matrix * fixed_rotation * U
        crystal.set_U(U)
        if params.space_group is not None:
            crystal.set_space_group(params.space_group.group())

    rows = []

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from scitbx import matrix
    R_to_mosflm = align_reference_frame(
        experiments[0].beam.get_s0(), (1.0, 0.0, 0.0),
        experiments[0].goniometer.get_rotation_axis(), (0.0, 0.0, 1.0))

    axes = []
    angles = []

    for i in range(len(experiments) - 1):
        target_angle = experiments[i + 1].goniometer.get_angles()[i]
        if i == experiments[i].goniometer.get_scan_axis():
            # rotation axis is canonical in our coordinate system
            axis = experiments[i].goniometer.get_axes()[i]
            angle = target_angle
        else:
            R_ij, axis, angle, cb_op = difference_rotation_matrix_axis_angle(
                experiments[i].crystal,
                experiments[i + 1].crystal,
                target_angle=target_angle)
        gonio = experiments[i + 1].goniometer
        axis_names = gonio.get_names()
        axes.append(axis)
        angles.append(angle)
        depends_on = '.'
        if i + 1 < len(axis_names):
            depends_on = axis_names[i + 1]
        rows.insert(
            0, (axis_names[i], 'rotation', 'goniometer', depends_on, '%.4f' %
                axis[0], '%.4f' % axis[1], '%.4f' % axis[2], '.', '.', '.'))

    axis_names = experiments[0].goniometer.get_names()
    print "Goniometer axes and angles (ImgCIF coordinate system):"
    for axis, angle, name in zip(axes, angles, axis_names):
        print "%s: " % name, "rotation of %.3f degrees" % angle, "about axis (%.5f,%.5f,%.5f)" % axis

    print
    print "Goniometer axes and angles (MOSFLM coordinate system):"
    for axis, angle, name in zip(axes, angles, axis_names):
        print "%s: " % name, "rotation of %.3f degrees" % angle, "about axis (%.5f,%.5f,%.5f)" % (
            R_to_mosflm * matrix.col(axis)).elems

    print
    print "ImgCIF _axis loop template:"
    from iotbx import cif
    loop = cif.model.loop(header=[
        '_axis.id', '_axis.type', '_axis.equipment', '_axis.depends_on',
        '_axis.vector[1]', '_axis.vector[2]', '_axis.vector[3]',
        '_axis.offset[1]', '_axis.offset[2]', '_axis.offset[3]'
    ])
    for row in rows:
        loop.add_row(row)

    print loop

    if params.output.xoalign is not None:
        axes_mosflm = [(R_to_mosflm * matrix.col(axis)).elems for axis in axes]
        write_xoalign_config(params.output.xoalign, reversed(axes_mosflm),
                             reversed(axis_names))
Ejemplo n.º 29
0
def dump(experiments, directory):
  '''
  Dump the experiments in mosflm format

  :param experiments: The experiments to dump
  :param directory: The directory to write to

  '''
  for i in range(len(experiments)):
    suffix = ""
    if len(experiments) > 1:
      suffix = "_%i" %(i+1)

    sub_dir = "%s%s" % (directory, suffix)
    if not os.path.isdir(sub_dir):
      os.makedirs(sub_dir)
    detector = experiments[i].detector
    beam = experiments[i].beam
    scan = experiments[i].scan
    goniometer = experiments[i].goniometer

    # XXX imageset is getting the experimental geometry from the image files
    # rather than the input experiments.json file
    imageset = experiments[i].imageset

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    R_to_mosflm = align_reference_frame(
      beam.get_s0(), (1.0, 0.0, 0.0),
      goniometer.get_rotation_axis(), (0.0, 0.0, 1.0))
    #print R_to_mosflm

    cryst = experiments[i].crystal
    cryst = cryst.change_basis(
      cryst.get_space_group().info()\
        .change_of_basis_op_to_reference_setting())
    A = cryst.get_A()
    A_inv = A.inverse()

    real_space_a = R_to_mosflm * A_inv.elems[:3]
    real_space_b = R_to_mosflm * A_inv.elems[3:6]
    real_space_c = R_to_mosflm * A_inv.elems[6:9]

    cryst_mosflm = crystal_model(
      real_space_a, real_space_b, real_space_c,
      space_group=cryst.get_space_group(),
      mosaicity=cryst.get_mosaicity())
    A_mosflm = cryst_mosflm.get_A()
    U_mosflm = cryst_mosflm.get_U()
    assert U_mosflm.is_r3_rotation_matrix(), U_mosflm
    w = beam.get_wavelength()

    index_mat = os.path.join(sub_dir, "index.mat")
    mosflm_in = os.path.join(sub_dir, "mosflm.in")
    print "Exporting experiment to %s and %s" %(index_mat, mosflm_in)

    with open(index_mat, "wb") as f:
      print >> f, format_mosflm_mat(w*A_mosflm, U_mosflm, cryst.get_unit_cell())

    directory, template = os.path.split(imageset.get_template())
    symmetry = cryst_mosflm.get_space_group().type().number()
    beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
    distance = detector[0].get_distance()

    with open(mosflm_in, "wb") as f:
      print >> f, write_mosflm_input(directory=directory,
                                     template=template,
                                     symmetry=symmetry,
                                     beam_centre=beam_centre,
                                     distance=distance,
                                     mat_file="index.mat")

  return
Ejemplo n.º 30
0
def run(args):

  from dials.util.options import OptionParser
  from dials.util.options import flatten_experiments
  from dials.util.options import flatten_reflections
  import libtbx.load_env

  usage = "%s [options] datablock.json" %(
    libtbx.env.dispatcher_name)

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

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

  if (len(reflections) == 0 or len(experiments) == 0):
    parser.print_help()
    exit(0)

  reflections = reflections[0]
  assert len(experiments) == 1

  experiment = experiments[0]

  from dials.command_line.check_strategy import filter_shadowed_reflections
  sel = filter_shadowed_reflections(experiments, reflections)
  print "%i/%i (%.2f%%) shadowed reflections" %(
    sel.count(True), sel.size(), 100*sel.count(True)/sel.size())

  if params.negate:
    sel = ~sel
  shadowed = reflections.select(sel)
  shadowed.as_pickle(params.output.reflections)

  if params.output.filter_hkl is not None:

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from scitbx import matrix
    detector = experiment.detector

    if len(detector) > 1:
      fast = detector[0].get_parent_fast_axis()
      slow = detector[0].get_parent_slow_axis()
      Rd = align_reference_frame(fast, (1,0,0), slow, (0,1,0))
      origin = Rd * matrix.col(detector[0].get_parent_origin())
    else:
      fast = detector[0].get_fast_axis()
      slow = detector[0].get_slow_axis()
      Rd = align_reference_frame(fast, (1,0,0), slow, (0,1,0))
      origin = Rd * matrix.col(detector[0].get_origin())

    with open(params.output.filter_hkl, 'wb') as f:

      for ref in shadowed:
        p = detector[ref['panel']]
        ox, oy = p.get_raw_image_offset()
        h, k, l = ref['miller_index']
        x, y, z = ref['xyzcal.px']
        dx, dy, dz = (2, 2, 2)
        print >> f, "%i %i %i %.1f %.1f %.1f %.1f %.1f %.1f" %(
          h, k, l, x+ox, y+oy, z, dx, dy, dz)
Ejemplo n.º 31
0
def export_xds_ascii(integrated_data,
                     experiment_list,
                     hklout,
                     summation=False,
                     include_partials=False,
                     keep_partials=False,
                     var_model=(1, 0)):
    '''Export data from integrated_data corresponding to experiment_list to
  an XDS_ASCII.HKL formatted text file.'''

    from dials.array_family import flex

    # for the moment assume (and assert) that we will convert data from exactly
    # one lattice...

    assert (len(experiment_list) == 1)
    # select reflections that are assigned to an experiment (i.e. non-negative id)

    integrated_data = integrated_data.select(integrated_data['id'] >= 0)
    assert max(integrated_data['id']) == 0

    if not summation:
        assert ('intensity.prf.value' in integrated_data)

    if 'intensity.prf.variance' in integrated_data:
        selection = integrated_data.get_flags(integrated_data.flags.integrated,
                                              all=True)
    else:
        selection = integrated_data.get_flags(
            integrated_data.flags.integrated_sum)
    integrated_data = integrated_data.select(selection)

    selection = integrated_data['intensity.sum.variance'] <= 0
    if selection.count(True) > 0:
        integrated_data.del_selected(selection)
        logger.info('Removing %d reflections with negative variance' % \
              selection.count(True))

    if 'intensity.prf.variance' in integrated_data:
        selection = integrated_data['intensity.prf.variance'] <= 0
        if selection.count(True) > 0:
            integrated_data.del_selected(selection)
            logger.info('Removing %d profile reflections with negative variance' % \
                  selection.count(True))

    if include_partials:
        integrated_data = sum_partial_reflections(integrated_data)
        integrated_data = scale_partial_reflections(integrated_data)

    if 'partiality' in integrated_data:
        selection = integrated_data['partiality'] < 0.99
        if selection.count(True) > 0 and not keep_partials:
            integrated_data.del_selected(selection)
            logger.info('Removing %d incomplete reflections' % \
              selection.count(True))

    experiment = experiment_list[0]

    # sort data before output
    nref = len(integrated_data['miller_index'])
    indices = flex.size_t_range(nref)

    import copy
    unique = copy.deepcopy(integrated_data['miller_index'])
    from cctbx.miller import map_to_asu
    map_to_asu(experiment.crystal.get_space_group().type(), False, unique)

    perm = sorted(indices, key=lambda k: unique[k])
    integrated_data = integrated_data.select(flex.size_t(perm))

    from scitbx import matrix
    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

    assert (not experiment.goniometer is None)

    unit_cell = experiment.crystal.get_unit_cell()

    from scitbx.array_family import flex
    from math import sqrt

    assert (not experiment.scan is None)
    image_range = experiment.scan.get_image_range()
    phi_start, phi_range = experiment.scan.get_image_oscillation(
        image_range[0])

    # gather the required information for the reflection file

    nref = len(integrated_data['miller_index'])
    zdet = flex.double(integrated_data['xyzcal.px'].parts()[2])

    miller_index = integrated_data['miller_index']

    I = None
    sigI = None

    # export including scale factors

    if 'lp' in integrated_data:
        lp = integrated_data['lp']
    else:
        lp = flex.double(nref, 1.0)
    if 'dqe' in integrated_data:
        dqe = integrated_data['dqe']
    else:
        dqe = flex.double(nref, 1.0)
    scl = lp / dqe

    # profile correlation
    if 'profile.correlation' in integrated_data:
        prof_corr = 100.0 * integrated_data['profile.correlation']
    else:
        prof_corr = flex.double(nref, 100.0)

    # partiality
    if 'partiality' in integrated_data:
        partiality = 100 * integrated_data['partiality']
    else:
        prof_corr = flex.double(nref, 100.0)

    if summation:
        I = integrated_data['intensity.sum.value'] * scl
        V = integrated_data['intensity.sum.variance'] * scl * scl
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)
    else:
        I = integrated_data['intensity.prf.value'] * scl
        V = integrated_data['intensity.prf.variance'] * scl * scl
        assert V.all_gt(0)
        V = var_model[0] * (V + var_model[1] * I * I)
        sigI = flex.sqrt(V)

    fout = open(hklout, 'w')

    # first write the header - in the "standard" coordinate frame...

    panel = experiment.detector[0]
    fast = panel.get_fast_axis()
    slow = panel.get_slow_axis()
    Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0))
    print 'Coordinate change:'
    print '%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n' % Rd.elems

    fast = Rd * fast
    slow = Rd * slow

    qx, qy = panel.get_pixel_size()
    nx, ny = panel.get_image_size()
    distance = matrix.col(Rd * panel.get_origin()).dot(
        matrix.col(Rd * panel.get_normal()))
    org = Rd * (matrix.col(panel.get_origin()) -
                distance * matrix.col(panel.get_normal()))
    orgx = -org.dot(fast) / qx
    orgy = -org.dot(slow) / qy

    UB = Rd * matrix.sqr(experiment.crystal.get_A())
    real_space_ABC = UB.inverse().elems

    axis = Rd * experiment.goniometer.get_rotation_axis()
    beam = Rd * experiment.beam.get_s0()
    cell_fmt = '%9.3f %9.3f %9.3f %7.3f %7.3f %7.3f'
    axis_fmt = '%9.3f %9.3f %9.3f'

    fout.write('\n'.join([
        '!FORMAT=XDS_ASCII    MERGE=FALSE    FRIEDEL\'S_LAW=TRUE',
        '!Generated by dials.export',
        '!DATA_RANGE= %d %d' % image_range,
        '!ROTATION_AXIS= %9.6f %9.6f %9.6f' % axis.elems,
        '!OSCILLATION_RANGE= %f' % phi_range,
        '!STARTING_ANGLE= %f' % phi_start,
        '!STARTING_FRAME= %d' % image_range[0],
        '!SPACE_GROUP_NUMBER= %d' %
        experiment.crystal.get_space_group().type().number(),
        '!UNIT_CELL_CONSTANTS= %s' % (cell_fmt % unit_cell.parameters()),
        '!UNIT_CELL_A-AXIS= %s' % (axis_fmt % real_space_ABC[0:3]),
        '!UNIT_CELL_B-AXIS= %s' % (axis_fmt % real_space_ABC[3:6]),
        '!UNIT_CELL_C-AXIS= %s' % (axis_fmt % real_space_ABC[6:9]),
        '!X-RAY_WAVELENGTH= %f' % experiment.beam.get_wavelength(),
        '!INCIDENT_BEAM_DIRECTION= %f %f %f' % beam.elems,
        '!NX= %d NY= %d QX= %f QY= %f' % (nx, ny, qx, qy),
        '!ORGX= %9.2f ORGY= %9.2f' % (orgx, orgy),
        '!DETECTOR_DISTANCE= %8.3f' % distance,
        '!DIRECTION_OF_DETECTOR_X-AXIS= %9.5f %9.5f %9.5f' % fast.elems,
        '!DIRECTION_OF_DETECTOR_Y-AXIS= %9.5f %9.5f %9.5f' % slow.elems,
        '!VARIANCE_MODEL= %7.3e %7.3e' % var_model,
        '!NUMBER_OF_ITEMS_IN_EACH_DATA_RECORD=12', '!ITEM_H=1', '!ITEM_K=2',
        '!ITEM_L=3', '!ITEM_IOBS=4', '!ITEM_SIGMA(IOBS)=5', '!ITEM_XD=6',
        '!ITEM_YD=7', '!ITEM_ZD=8', '!ITEM_RLP=9', '!ITEM_PEAK=10',
        '!ITEM_CORR=11', '!ITEM_PSI=12', '!END_OF_HEADER', ''
    ]))

    # then write the data records

    s0 = Rd * matrix.col(experiment.beam.get_s0())

    for j in range(nref):
        x, y, z = integrated_data['xyzcal.px'][j]
        phi = phi_start + z * phi_range
        h, k, l = miller_index[j]
        X = (UB * (h, k, l)).rotate(axis, phi, deg=True)
        s = s0 + X
        g = s.cross(s0).normalize()
        f = (s - s0).normalize()

        # find component of beam perpendicular to f, e
        e = -(s + s0).normalize()
        if h == k and k == l:
            u = (h, -h, 0)
        else:
            u = (k - l, l - h, h - k)
        q = (matrix.col(u).transpose() *
             UB.inverse()).normalize().transpose().rotate(axis, phi, deg=True)

        psi = q.angle(g, deg=True)
        if q.dot(e) < 0:
            psi *= -1

        fout.write('%d %d %d %f %f %f %f %f %f %.1f %.1f %f\n' %
                   (h, k, l, I[j], sigI[j], x, y, z, scl[j], partiality[j],
                    prof_corr[j], psi))

    fout.write('!END_OF_DATA\n')
    fout.close()
    logger.info('Output %d reflections to %s' % (nref, hklout))
Ejemplo n.º 32
0
Archivo: best.py Proyecto: dials/dials
def write_par_file(file_name, experiment):
  from scitbx import matrix
  from dxtbx.model.crystal import crystal_model
  from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
  from iotbx.mtz.extract_from_symmetry_lib import ccp4_symbol

  imageset = experiment.imageset
  detector = imageset.get_detector()
  goniometer = imageset.get_goniometer()
  beam = imageset.get_beam()
  scan = imageset.get_scan()

  R_to_mosflm = align_reference_frame(
    beam.get_s0(), (1.0, 0.0, 0.0),
    goniometer.get_rotation_axis(), (0.0, 0.0, 1.0))

  cryst = experiment.crystal
  cryst = cryst.change_basis(
    cryst.get_space_group().info()\
      .change_of_basis_op_to_reference_setting())
  A = cryst.get_A()
  A_inv = A.inverse()

  real_space_a = R_to_mosflm * A_inv.elems[:3]
  real_space_b = R_to_mosflm * A_inv.elems[3:6]
  real_space_c = R_to_mosflm * A_inv.elems[6:9]

  cryst_mosflm = crystal_model(
    real_space_a, real_space_b, real_space_c,
    space_group=cryst.get_space_group(),
    mosaicity=cryst.get_mosaicity())
  A_mosflm = cryst_mosflm.get_A()
  U_mosflm = cryst_mosflm.get_U()
  B_mosflm = cryst_mosflm.get_B()
  UB_mosflm = U_mosflm * B_mosflm
  uc_params = cryst_mosflm.get_unit_cell().parameters()
  assert U_mosflm.is_r3_rotation_matrix(), U_mosflm

  symmetry = cryst_mosflm.get_space_group().type().number()
  beam_centre = tuple(reversed(detector[0].get_beam_centre(beam.get_s0())))
  distance = detector[0].get_directed_distance()
  polarization = R_to_mosflm * matrix.col(beam.get_polarization_normal())
  rotation = matrix.col(goniometer.get_rotation_axis())
  if (rotation.angle(matrix.col(detector[0].get_fast_axis())) <
      rotation.angle(matrix.col(detector[0].get_slow_axis()))):
    direction = 'FAST'
  else:
    direction = 'SLOW'
  rotation = R_to_mosflm * rotation

  with open(file_name, 'wb') as f:#
    print >> f, '# parameter file for BEST'
    print >> f, 'TITLE          From DIALS'
    print >> f, 'DETECTOR       PILA'
    print >> f, 'SITE           Not set'
    print >> f, 'DIAMETER       %6.2f' %(max(detector[0].get_image_size()) * detector[0].get_pixel_size()[0])
    print >> f, 'PIXEL          %s' %detector[0].get_pixel_size()[0]
    print >> f, 'ROTAXIS        %4.2f %4.2f %4.2f' %rotation.elems, direction
    print >> f, 'POLAXIS        %4.2f %4.2f %4.2f' %polarization.elems
    print >> f, 'GAIN               1.00' # correct for Pilatus images
    print >> f, 'CMOSAIC            %.2f' %experiment.profile.sigma_m()
    print >> f, 'PHISTART           %.2f' %scan.get_oscillation_range()[0]
    print >> f, 'PHIWIDTH           %.2f' %scan.get_oscillation()[1]
    print >> f, 'DISTANCE        %7.2f' %distance
    print >> f, 'WAVELENGTH      %.5f' %beam.get_wavelength()
    print >> f, 'POLARISATION    %7.5f' %beam.get_polarization_fraction()
    print >> f, 'SYMMETRY       %s' %ccp4_symbol(
      cryst.get_space_group().info(), lib_name='syminfo.lib',
       require_at_least_one_lib=False).replace(' ', '')
    print >> f, 'UB             %9.6f %9.6f %9.6f' %UB_mosflm[:3]
    print >> f, '               %9.6f %9.6f %9.6f' %UB_mosflm[3:6]
    print >> f, '               %9.6f %9.6f %9.6f' %UB_mosflm[6:]
    print >> f, 'CELL           %8.2f %8.2f %8.2f %6.2f %6.2f %6.2f' %uc_params
    print >> f, 'RASTER           13  13   7   3   4'
    print >> f, 'SEPARATION      2.960  2.960'
    print >> f, 'BEAM           %8.3f %8.3f' %beam_centre
    print >> f, '# end of parameter file for BEST'
Ejemplo n.º 33
0
def run(args=None):
    from dials.util.options import OptionParser, flatten_experiments

    usage = "dials.goniometer_calibration [options] models.expt"

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

    params, options = parser.parse_args(args, show_diff_phil=True)
    if not params.use_space_group_from_experiments and params.space_group is None:
        parser.print_help()
        return

    experiments = flatten_experiments(params.input.experiments)
    if len(experiments) <= 1:
        parser.print_help()
        return

    from dials.algorithms.indexing.compare_orientation_matrices import (
        difference_rotation_matrix_axis_angle, )

    for experiment in experiments:
        crystal = experiment.crystal
        gonio = experiment.goniometer
        assert len(experiments) == (len(gonio.get_axes()) + 1)
        scan = experiment.scan
        fixed_rotation = matrix.sqr(gonio.get_fixed_rotation())
        setting_rotation = matrix.sqr(gonio.get_setting_rotation())
        rotation_axis = matrix.col(gonio.get_rotation_axis_datum())
        rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix(
            scan.get_oscillation()[0], deg=True)
        U = matrix.sqr(crystal.get_U())
        U = setting_rotation * rotation_matrix * fixed_rotation * U
        crystal.set_U(U)
        if params.space_group is not None:
            crystal.set_space_group(params.space_group.group())

    rows = []

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame

    R_to_mosflm = align_reference_frame(
        experiments[0].beam.get_s0(),
        (1.0, 0.0, 0.0),
        experiments[0].goniometer.get_rotation_axis(),
        (0.0, 0.0, 1.0),
    )

    axes = []
    angles = []

    for i in range(len(experiments) - 1):
        target_angle = experiments[i + 1].goniometer.get_angles()[i]
        if i == experiments[i].goniometer.get_scan_axis():
            # rotation axis is canonical in our coordinate system
            axis = experiments[i].goniometer.get_axes()[i]
            angle = target_angle
        else:
            R_ij, axis, angle, cb_op = difference_rotation_matrix_axis_angle(
                experiments[i].crystal,
                experiments[i + 1].crystal,
                target_angle=target_angle,
            )
        gonio = experiments[i + 1].goniometer
        axis_names = gonio.get_names()
        axes.append(axis)
        angles.append(angle)
        depends_on = "."
        if i + 1 < len(axis_names):
            depends_on = axis_names[i + 1]
        rows.insert(
            0,
            (
                axis_names[i],
                "rotation",
                "goniometer",
                depends_on,
                f"{axis[0]:.4f}",
                f"{axis[1]:.4f}",
                f"{axis[2]:.4f}",
                ".",
                ".",
                ".",
            ),
        )

    axis_names = experiments[0].goniometer.get_names()
    print("Goniometer axes and angles (ImgCIF coordinate system):")
    for axis, angle, name in zip(axes, angles, axis_names):
        print(
            f"{name}: ",
            f"rotation of {angle:.3f} degrees",
            "about axis (%.5f,%.5f,%.5f)" % axis,
        )

    print()
    print("Goniometer axes and angles (MOSFLM coordinate system):")
    for axis, angle, name in zip(axes, angles, axis_names):
        print(
            f"{name}: ",
            f"rotation of {angle:.3f} degrees",
            "about axis (%.5f,%.5f,%.5f)" %
            (R_to_mosflm * matrix.col(axis)).elems,
        )

    print()
    print("ImgCIF _axis loop template:")
    from iotbx import cif

    loop = cif.model.loop(header=[
        "_axis.id",
        "_axis.type",
        "_axis.equipment",
        "_axis.depends_on",
        "_axis.vector[1]",
        "_axis.vector[2]",
        "_axis.vector[3]",
        "_axis.offset[1]",
        "_axis.offset[2]",
        "_axis.offset[3]",
    ])
    for row in rows:
        loop.add_row(row)

    print(loop)

    if params.output.xoalign is not None:
        axes_mosflm = [(R_to_mosflm * matrix.col(axis)).elems for axis in axes]
        write_xoalign_config(params.output.xoalign, reversed(axes_mosflm),
                             reversed(axis_names))
Ejemplo n.º 34
0
    def __init__(self, experiment, vectors, frame="reciprocal", mode="main"):
        from dials.util import Sorry

        self.experiment = experiment
        self.vectors = vectors
        self.frame = frame
        self.mode = mode

        gonio = experiment.goniometer

        self.s0 = matrix.col(self.experiment.beam.get_s0())
        self.rotation_axis = matrix.col(gonio.get_rotation_axis())

        from dxtbx.model import MultiAxisGoniometer

        if not isinstance(gonio, MultiAxisGoniometer):
            raise Sorry("Only MultiAxisGoniometer models supported")
        axes = gonio.get_axes()
        if len(axes) != 3:
            raise Sorry("Only 3-axis goniometers supported")
        e1, e2, e3 = (matrix.col(e) for e in reversed(axes))

        # fixed_rotation = matrix.sqr(gonio.get_fixed_rotation())
        # setting_rotation = matrix.sqr(gonio.get_setting_rotation())
        # rotation_axis = matrix.col(gonio.get_rotation_axis_datum())
        # rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix(
        #    experiment.scan.get_oscillation()[0], deg=True
        # )

        from dials.algorithms.refinement import rotation_decomposition

        results = []

        # from https://github.com/legrandp/xdsme/blob/master/XOalign/XOalign.py#L427
        #  referential_permutations sign permutations for four permutations of
        #        parallel/antiparallel (rotation axis & beam)
        #    y1 // e1, y2 // beamVector;  y1 anti// e1, y2 // beamVector
        #    y1 // e1, y2 anti// beamVector;  y1 anti// e1, y2 anti// beamVector

        ex = matrix.col((1, 0, 0))
        ey = matrix.col((0, 1, 0))
        ez = matrix.col((0, 0, 1))

        referential_permutations = (
            [ex, ey, ez],
            [-ex, -ey, ez],
            [ex, -ey, -ez],
            [-ex, ey, -ez],
        )

        for (v1_, v2_) in self.vectors:
            result_dictionary = collections.OrderedDict()
            results.append((v1_, v2_, result_dictionary))
            space_group = self.experiment.crystal.get_space_group()
            for smx in list(space_group.smx())[:]:
                result_dictionary[smx] = []
                crystal = copy.deepcopy(self.experiment.crystal)
                cb_op = sgtbx.change_of_basis_op(smx)
                crystal = crystal.change_basis(cb_op)

                # Goniometer datum setting [D] at which the orientation was determined
                # D = (setting_rotation * rotation_matrix * fixed_rotation).inverse()

                # The setting matrix [U] will vary with the datum setting according to
                # [U] = [D] [U0]
                U = matrix.sqr(crystal.get_U())

                # XXX In DIALS recorded U is equivalent to U0 - D is applied to U inside
                # prediction
                U0 = U

                B = matrix.sqr(crystal.get_B())

                if self.frame == "direct":
                    B = B.inverse().transpose()

                v1_0 = U0 * B * v1_
                v2_0 = U0 * B * v2_

                # c  (b) The laboratory frame vectors l1 & l2 are normally specified with the
                # c MODE command: MODE MAIN (the default) sets l1 (along which v1 will be
                # c placed) along the principle goniostat axis e1 (Omega), and l2 along
                # c the beam s0. This allows rotation for instance around a principle axis.
                # c The other mode is MODE CUSP, which puts l1 (v1) perpendicular to the
                # c beam (s0) and the e1 (Omega) axis, and l2 (v2) in the plane containing
                # c l1 & e1 (ie l1 = e1 x s0, l2 = e1).

                if self.mode == "cusp":
                    l1 = self.rotation_axis.cross(self.s0)
                    l2 = self.rotation_axis
                else:
                    l1 = self.rotation_axis.normalize()
                    l3 = l1.cross(self.s0).normalize()
                    l2 = l1.cross(l3)

                for perm in referential_permutations:
                    S = matrix.sqr(perm[0].elems + perm[1].elems +
                                   perm[2].elems)
                    from rstbx.cftbx.coordinate_frame_helpers import (
                        align_reference_frame, )

                    R = align_reference_frame(v1_0, S * l1, v2_0, S * l2)

                    solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes(
                        R, e1, e2, e3, return_both_solutions=True, deg=True)

                    if solutions is None:
                        continue

                    result_dictionary[smx].extend(solutions)

        self.all_solutions = results

        self.unique_solutions = collections.OrderedDict()
        for v1, v2, result in results:
            for solutions in result.values():
                for solution in solutions:
                    k = tuple(round(a, 3) for a in solution[1:])
                    self.unique_solutions.setdefault(k, [])
                    if all(v1 != z1 or v2 != z2
                           for z1, z2 in self.unique_solutions[k]):
                        self.unique_solutions[k].append((v1, v2))
  def get_goniometer_shadow_masker(self, goniometer=None):
    from dials.util.masking import GoniometerShadowMaskGenerator
    from scitbx.array_family import flex
    import math

    coords = flex.vec3_double((
      (0,0,0),
    ))

    alpha = flex.double_range(0, 190, step=10) * math.pi / 180
    r = flex.double(alpha.size(), 40)
    x = flex.double(r.size(), 107.61)
    y = -r*flex.sin(alpha)
    z = -r*flex.cos(alpha)
    coords.extend(flex.vec3_double(x, y, z))

    coords.extend(flex.vec3_double((
      # fixed
      (107.49, 7.84, 39.49),
      (107.39, 15.69, 38.97),
      (107.27, 23.53, 38.46),
      (107.16, 31.37, 37.94),
      (101.76, 33.99, 36.25),
      (96.37, 36.63, 34.56),
      (90.98, 39.25, 33.00),
      (85.58, 41.88, 31.18),
      (80.89, 47.06, 31.00),
      (76.55, 51.51, 31.03),
      (72.90, 55.04, 31.18),
      (66.86, 60.46, 31.67),
      (62.10, 64.41, 32.25),
    )))

    alpha = flex.double_range(180, 370, step=10) * math.pi / 180
    r = flex.double(alpha.size(), 33)
    x = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.cos((50 * math.pi/180) - flex.atan(r/89.02 * flex.sin(alpha))))
    y = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.sin((50 * math.pi/180) - flex.atan(r/89.02 * flex.sin(alpha))))
    z = -r*flex.cos(alpha)
    coords.extend(flex.vec3_double(x, y, z))

    coords.extend(flex.vec3_double((
      # fixed
      (62.10, 64.41, -32.25),
      (66.86, 60.46, -31.67),
      (72.90, 55.04, -31.18),
      (76.55, 51.51, -31.03),
      (80.89, 47.06, -31.00),
      (85.58, 41.88, -31.18),
      (90.98, 39.25, -33.00),
      (96.37, 36.63, -34.56),
      (101.76, 33.99, -36.25),
      (107.16, 31.37, -37.94),
      (107.27, 23.53, -38.46),
      (107.39, 15.69, -38.97),
      (107.49, 7.84, -39.49),
      (107.61, 0.00, -40.00)
    )))

    # I23 end station coordinate system:
    #   X-axis: positive direction is facing away from the storage ring (from
    #           sample towards goniometer)
    #   Y-axis: positive direction is vertically up
    #   Z-axis: positive direction is in the direction of the beam (from
    #           sample towards detector)
    #   K-axis (kappa): at an angle of +50 degrees from the X-axis
    #   K & phi rotation axes: clockwise rotation is positive (right hand
    #           thumb rule)
    #   Omega-axis: along the X-axis; clockwise rotation is positive

    # End station x-axis is parallel to ImgCIF x-axis
    # End station z-axis points in opposite direction to ImgCIF definition
    # (ImgCIF: The Z-axis is derived from the source axis which goes from
    # the sample to the source)
    # Consequently end station y-axis (to complete set following right hand
    # rule) points in opposite direction to ImgCIF y-axis.
    # Kappa arm aligned with -y in ImgCIF convention

    from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame
    from scitbx import matrix
    R = align_reference_frame(matrix.col((1,0,0)), matrix.col((1,0,0)),
                              matrix.col((0,1,0)), matrix.col((0,-1,0)))
    coords = R.elems * coords

    if goniometer is None:
      goniometer = self.get_goniometer()
    return GoniometerShadowMaskGenerator(
      goniometer, coords, flex.size_t(len(coords), 1))