Ejemplo n.º 1
0
        def continue_from_error(self):
            # copy the LP file
            shutil.copyfile(
                os.path.join(self.get_working_directory(), "IDXREF.LP"),
                os.path.join(
                    self.get_working_directory(), "%d_IDXREF.LP" % self.get_xpid()
                ),
            )

            # parse the output
            lp = open(
                os.path.join(self.get_working_directory(), "IDXREF.LP"), "r"
            ).readlines()

            self._fraction_rmsd_rmsphi = _parse_idxref_lp_quality(lp)

            self._idxref_data = _parse_idxref_lp(lp)

            if not self._idxref_data:
                raise RuntimeError("indexing failed")

            st = _parse_idxref_lp_subtree(lp)

            if 2 in st:

                if st[2] > st[1] / 10.0:
                    Debug.write("Look closely at autoindexing solution!")
                    self._index_tree_problem = True
                    for j in sorted(st):
                        Debug.write("%2d: %5d" % (j, st[j]))

            # print out some (perhaps dire) warnings about the beam centre
            # if there is really any ambiguity...

            origins = _parse_idxref_index_origin(lp)

            assert (0, 0, 0) in origins

            quality_0 = origins[(0, 0, 0)][0]

            alternatives = []

            for hkl in origins:
                if hkl == (0, 0, 0):
                    continue
                if origins[hkl][0] < 4 * quality_0:
                    quality, delta, beam_x, beam_y = origins[hkl]
                    alternatives.append(
                        (hkl[0], hkl[1], hkl[2], quality, beam_x, beam_y)
                    )

            if alternatives:
                Debug.write("Alternative indexing possible:")
                for alternative in alternatives:
                    Debug.write("... %3d %3d %3d %4.1f %6.1f %6.1f" % alternative)

            # New algorithm in here - now use iotbx.lattice_symmetry with the
            # P1 indexing solution (solution #1) to determine the list of
            # allowable solutions - only consider those lattices in this
            # allowed list (unless we have user input)

            from xia2.Wrappers.Phenix.LatticeSymmetry import LatticeSymmetry

            ls = LatticeSymmetry()
            ls.set_lattice("aP")
            ls.set_cell(tuple(self._idxref_data[44]["cell"]))
            ls.generate()

            allowed_lattices = ls.get_lattices()

            for j in range(1, 45):
                if j not in self._idxref_data:
                    continue
                data = self._idxref_data[j]
                lattice = data["lattice"]
                fit = data["fit"]
                cell = data["cell"]
                mosaic = data["mosaic"]

                if self._symm and self._cell and self._indxr_user_input_lattice:

                    if (
                        self._compare_cell(self._cell, cell)
                        and lattice_to_spacegroup_number(lattice) == self._symm
                    ):
                        if lattice in self._indexing_solutions:
                            if self._indexing_solutions[lattice]["goodness"] < fit:
                                continue

                        self._indexing_solutions[lattice] = {
                            "goodness": fit,
                            "cell": cell,
                        }

                else:
                    if lattice in allowed_lattices or (self._symm and fit < 200.0):
                        # bug 2417 - if we have an input lattice then we
                        # don't want to include anything higher symmetry
                        # in the results table...

                        if self._symm:
                            if lattice_to_spacegroup_number(lattice) > self._symm:
                                Debug.write(
                                    "Ignoring solution with lattice %s" % lattice
                                )
                                continue

                        if lattice in self._indexing_solutions:
                            if self._indexing_solutions[lattice]["goodness"] < fit:
                                continue

                        self._indexing_solutions[lattice] = {
                            "goodness": fit,
                            "cell": cell,
                        }

            # postprocess this list, to remove lattice solutions which are
            # lower symmetry but higher penalty than the putative correct
            # one, if self._symm is set...

            if self._symm:
                assert self._indexing_solutions, (
                    "No remaining indexing solutions (%s, %s)"
                    % (s2l(self._symm), self._symm)
                )
            else:
                assert self._indexing_solutions, "No remaining indexing solutions"

            if self._symm:
                max_p = 2.0 * self._indexing_solutions[s2l(self._symm)]["goodness"]
                to_remove = []
                for lattice in self._indexing_solutions:
                    if self._indexing_solutions[lattice]["goodness"] > max_p:
                        to_remove.append(lattice)
                for lattice in to_remove:
                    Debug.write("Ignoring solution with lattice %s" % lattice)
                    del self._indexing_solutions[lattice]

            # get the highest symmetry "acceptable" solution

            items = [
                (k, self._indexing_solutions[k]["cell"])
                for k in self._indexing_solutions
            ]

            # if there was a preassigned cell and symmetry return now
            # with everything done, else select the "top" solution and
            # reindex, resetting the input cell and symmetry.

            if self._cell:

                # select the solution which matches the input unit cell
                # actually after the changes above this should now be the
                # only solution in the table..

                Debug.write(
                    "Target unit cell: %.2f %.2f %.2f %.2f %.2f %.2f" % self._cell
                )

                for l in items:
                    if lattice_to_spacegroup_number(l[0]) == self._symm:
                        # this should be the correct solution...
                        # check the unit cell...
                        cell = l[1]

                        cell_str = "%.2f %.2f %.2f %.2f %.2f %.2f" % cell
                        Debug.write("Chosen unit cell: %s" % cell_str)

                        self._indxr_lattice = l[0]
                        self._indxr_cell = l[1]
                        self._indxr_mosaic = mosaic

            else:

                # select the top solution as the input cell and reset the
                # "indexing done" flag

                sorted_list = SortLattices(items)
                #       print sorted_list

                self._symm = lattice_to_spacegroup_number(sorted_list[0][0])
                self._cell = sorted_list[0][1]

                return False

            # get the refined distance &c.

            beam, distance = _parse_idxref_lp_distance_etc(lp)

            self._refined_beam = beam
            self._refined_distance = distance

            # gather the output files

            for file in self._output_data_files_list:
                self._output_data_files[file] = os.path.join(
                    self.get_working_directory(), file
                )

            return True
Ejemplo n.º 2
0
def mosflm_matrix_centred_to_primitive(lattice, mosflm_a_matrix):
  '''Convert a mosflm orientation matrix from a centred setting to a
  primitive one (i.e. same lattice, but without the centering operations,
  which therefore corresponds to a different basis).'''

  space_group_number = l2s(lattice)
  spacegroup = sgtbx.space_group_symbols(space_group_number).hall()
  sg = sgtbx.space_group(spacegroup)

  rtod = 180.0 / math.pi

  if not (sg.n_ltr() - 1):
    return mosflm_a_matrix

  cell, amat, umat = parse_matrix(mosflm_a_matrix)

  # first derive the wavelength

  mi = matrix.sqr(amat)
  m = mi.inverse()

  A = matrix.col(m.elems[0:3])
  B = matrix.col(m.elems[3:6])
  C = matrix.col(m.elems[6:9])

  a = math.sqrt(A.dot())
  b = math.sqrt(B.dot())
  c = math.sqrt(C.dot())

  alpha = rtod * B.angle(C)
  beta = rtod * C.angle(A)
  gamma = rtod * A.angle(B)

  wavelength = ((cell[0] / a) + (cell[1] / b) + (cell[2] / c)) / 3.0

  # then use this to rescale the A matrix

  mi = matrix.sqr([a / wavelength for a in amat])
  m = mi.inverse()

  sgp = sg.build_derived_group(True, False)
  lattice_p = s2l(sgp.type().number())
  symm = crystal.symmetry(unit_cell = cell,
                          space_group = sgp)

  rdx = symm.change_of_basis_op_to_best_cell()
  symm_new = symm.change_basis(rdx)

  # now apply this to the reciprocal-space orientation matrix mi

  cb_op = rdx
  R = cb_op.c_inv().r().as_rational().as_float().transpose().inverse()
  mi_r = mi * R

  # now re-derive the cell constants, just to be sure

  m_r = mi_r.inverse()
  Ar = matrix.col(m_r.elems[0:3])
  Br = matrix.col(m_r.elems[3:6])
  Cr = matrix.col(m_r.elems[6:9])

  a = math.sqrt(Ar.dot())
  b = math.sqrt(Br.dot())
  c = math.sqrt(Cr.dot())

  alpha = rtod * Br.angle(Cr)
  beta = rtod * Cr.angle(Ar)
  gamma = rtod * Ar.angle(Br)

  cell = uctbx.unit_cell((a, b, c, alpha, beta, gamma))

  amat = [wavelength * e for e in mi_r.elems]
  bmat = matrix.sqr(cell.fractionalization_matrix())
  umat = mi_r * bmat.inverse()

  new_matrix = ['%s\n' % r for r in \
                format_matrix((a, b, c, alpha, beta, gamma),
                              amat, umat.elems).split('\n')]

  return new_matrix
Ejemplo n.º 3
0
    def continue_from_error(self):
      # copy the LP file
      shutil.copyfile(os.path.join(self.get_working_directory(),
                                   'IDXREF.LP'),
                      os.path.join(self.get_working_directory(),
                                   '%d_IDXREF.LP' % self.get_xpid()))

      # parse the output
      lp = open(os.path.join(
          self.get_working_directory(), 'IDXREF.LP'), 'r').readlines()

      self._fraction_rmsd_rmsphi = _parse_idxref_lp_quality(lp)

      self._idxref_data = _parse_idxref_lp(lp)

      if not self._idxref_data:
        raise RuntimeError, 'indexing failed'

      st = _parse_idxref_lp_subtree(lp)

      if 2 in st:

        if st[2] > st[1] / 10.0:
          Debug.write('Look closely at autoindexing solution!')
          self._index_tree_problem = True
          for j in sorted(st):
            Debug.write('%2d: %5d' % (j, st[j]))

      # print out some (perhaps dire) warnings about the beam centre
      # if there is really any ambiguity...

      origins = _parse_idxref_index_origin(lp)

      assert((0, 0, 0) in origins)

      quality_0 = origins[(0, 0, 0)][0]

      alternatives = []

      for hkl in origins:
        if hkl == (0, 0, 0):
          continue
        if origins[hkl][0] < 4 * quality_0:
          quality, delta, beam_x, beam_y = origins[hkl]
          alternatives.append((hkl[0], hkl[1], hkl[2],
                               quality, beam_x, beam_y))

      if alternatives:
        Debug.write('Alternative indexing possible:')
        for alternative in alternatives:
          Debug.write('... %3d %3d %3d %4.1f %6.1f %6.1f' % \
                      alternative)

      # New algorithm in here - now use iotbx.lattice_symmetry with the
      # P1 indexing solution (solution #1) to determine the list of
      # allowable solutions - only consider those lattices in this
      # allowed list (unless we have user input)

      from xia2.Wrappers.Phenix.LatticeSymmetry import LatticeSymmetry
      ls = LatticeSymmetry()
      ls.set_lattice('aP')
      ls.set_cell(tuple(self._idxref_data[44]['cell']))
      ls.generate()

      allowed_lattices = ls.get_lattices()

      for j in range(1, 45):
        if j not in self._idxref_data:
          continue
        data = self._idxref_data[j]
        lattice = data['lattice']
        fit = data['fit']
        cell = data['cell']
        mosaic = data['mosaic']
        reidx = data['reidx']

        if self._symm and self._cell and \
               self._indxr_user_input_lattice:

          if self._compare_cell(self._cell, cell) and \
                 lattice_to_spacegroup_number(lattice) == self._symm:
            if lattice in self._indexing_solutions:
              if self._indexing_solutions[lattice][
                  'goodness'] < fit:
                continue

            self._indexing_solutions[lattice] = {
                'goodness':fit,
                'cell':cell}

        else:
          if lattice in allowed_lattices or \
              (self._symm and fit < 200.0):
            # bug 2417 - if we have an input lattice then we
            # don't want to include anything higher symmetry
            # in the results table...

            if self._symm:
              if lattice_to_spacegroup_number(lattice) \
                     > self._symm:
                Debug.write(
                    'Ignoring solution with lattice %s' % \
                    lattice)
                continue

            if lattice in self._indexing_solutions:
              if self._indexing_solutions[lattice][
                  'goodness'] < fit:
                continue

            self._indexing_solutions[lattice] = {
                'goodness':fit,
                'cell':cell}

      # postprocess this list, to remove lattice solutions which are
      # lower symmetry but higher penalty than the putative correct
      # one, if self._symm is set...

      if self._symm:
        assert len(self._indexing_solutions) > 0, "No remaining indexing solutions (%s, %s)" % (s2l(self._symm), self._symm);
      else:
        assert len(self._indexing_solutions) > 0, "No remaining indexing solutions"

#     print self._indexing_solutions
      if self._symm:
        max_p = 2.0 * self._indexing_solutions[
            s2l(self._symm)]['goodness']
        to_remove = []
        for lattice in self._indexing_solutions:
          if self._indexing_solutions[lattice]['goodness'] > max_p:
            to_remove.append(lattice)
        for lattice in to_remove:
          Debug.write('Ignoring solution with lattice %s' % \
                      lattice)
          del(self._indexing_solutions[lattice])


      # get the highest symmetry "acceptable" solution

      list = [(k, self._indexing_solutions[k]['cell']) for k in \
              self._indexing_solutions.keys()]

      # if there was a preassigned cell and symmetry return now
      # with everything done, else select the "top" solution and
      # reindex, resetting the input cell and symmetry.

      if self._cell:

        # select the solution which matches the input unit cell
        # actually after the changes above this should now be the
        # only solution in the table..

        Debug.write(
            'Target unit cell: %.2f %.2f %.2f %.2f %.2f %.2f' % \
            self._cell)

        for l in list:
          if lattice_to_spacegroup_number(l[0]) == self._symm:
            # this should be the correct solution...
            # check the unit cell...
            cell = l[1]

            if self._compare_cell(self._cell, cell) or True:

              cell_str = '%.2f %.2f %.2f %.2f %.2f %.2f' % cell
              Debug.write(
              'Chosen unit cell: %s' % cell_str)

              self._indxr_lattice = l[0]
              self._indxr_cell = l[1]
              self._indxr_mosaic = mosaic

            else:

              cell_str = '%.2f %.2f %.2f %.2f %.2f %.2f' % cell
              Debug.write(
              'Ignoring unit cell: %s' % cell_str)

      else:

        # select the top solution as the input cell and reset the
        # "indexing done" flag

        sorted_list = SortLattices(list)
#       print sorted_list

        self._symm = lattice_to_spacegroup_number(sorted_list[0][0])
        self._cell = sorted_list[0][1]

        return False

      # get the refined distance &c.

      beam, distance = _parse_idxref_lp_distance_etc(lp)

      self._refined_beam = beam
      self._refined_distance = distance

      # gather the output files

      for file in self._output_data_files_list:
        self._output_data_files[file] = os.path.join(
          self.get_working_directory(), file)

      return True
Ejemplo n.º 4
0
def xds_check_indexer_solution(xparm_file, spot_file):
    """Read XPARM file from XDS IDXREF (assumes that this is in the putative
    correct symmetry, not P1! and test centring operations if present. Note
    that a future version will boost to the putative correct symmetry (or
    an estimate of it) and try this if it is centred. Returns tuple
    (space_group_number, cell)."""

    cm = dxtbx.serialize.xds.to_crystal(xparm_file)
    sg = cm.get_space_group()
    space_group_number = sg.type().number()
    A_inv = matrix.sqr(cm.get_A()).inverse()
    cell = cm.get_unit_cell().parameters()

    models = dxtbx.load(xparm_file)
    detector = models.get_detector()
    beam = models.get_beam()
    goniometer = models.get_goniometer()
    scan = models.get_scan()

    spot_xds_handle = spot_xds.reader()
    spot_xds_handle.read_file(spot_file)

    centroids_px = flex.vec3_double(spot_xds_handle.centroid)

    # Convert Pixel coordinate into mm/rad
    x, y, z = centroids_px.parts()
    x_mm, y_mm = detector[0].pixel_to_millimeter(flex.vec2_double(x,
                                                                  y)).parts()
    z_rad = scan.get_angle_from_array_index(z, deg=False)

    # then convert detector position to reciprocal space position

    # based on code in dials/algorithms/indexing/indexer2.py
    s1 = detector[0].get_lab_coord(flex.vec2_double(x_mm, y_mm))
    s1 = s1 / s1.norms() * (1 / beam.get_wavelength())
    S = s1 - beam.get_s0()
    # XXX what about if goniometer fixed rotation is not identity?
    reciprocal_space_points = S.rotate_around_origin(
        goniometer.get_rotation_axis(), -z_rad)

    # now index the reflections
    hkl_float = tuple(A_inv) * reciprocal_space_points
    hkl_int = hkl_float.iround()

    # check if we are within 0.1 lattice spacings of the closest
    # lattice point - a for a random point this will be about 0.8% of
    # the time...
    differences = hkl_float - hkl_int.as_vec3_double()
    dh, dk, dl = [flex.abs(d) for d in differences.parts()]
    tolerance = 0.1
    sel = (dh < tolerance) and (dk < tolerance) and (dl < tolerance)

    is_sys_absent = sg.is_sys_absent(
        flex.miller_index(list(hkl_int.select(sel))))

    total = is_sys_absent.size()
    absent = is_sys_absent.count(True)
    present = total - absent

    # now, if the number of absences is substantial, need to consider
    # transforming this to a primitive basis

    logger.debug("Absent: %d  vs.  Present: %d Total: %d", absent, present,
                 total)

    # now see if this is compatible with a centred lattice or suggests
    # a primitive basis is correct

    sd = math.sqrt(absent)

    if (absent - 3 * sd) / total < 0.008:
        # everything is peachy

        return s2l(space_group_number), tuple(cell)

    # ok if we are here things are not peachy, so need to calculate the
    # spacegroup number without the translation operators

    sg_new = sg.build_derived_group(True, False)
    space_group_number_primitive = sg_new.type().number()

    # also determine the best setting for the new cell ...

    symm = crystal.symmetry(unit_cell=cell, space_group=sg_new)

    rdx = symm.change_of_basis_op_to_best_cell()
    symm_new = symm.change_basis(rdx)
    cell_new = symm_new.unit_cell().parameters()

    return s2l(space_group_number_primitive), tuple(cell_new)
Ejemplo n.º 5
0
def mosflm_check_indexer_solution(indexer):

  distance = indexer.get_indexer_distance()
  axis = matrix.col([0, 0, 1])
  beam = indexer.get_indexer_beam_centre()
  cell = indexer.get_indexer_cell()
  wavelength = indexer.get_wavelength()

  space_group_number = l2s(indexer.get_indexer_lattice())
  spacegroup = sgtbx.space_group_symbols(space_group_number).hall()
  phi = indexer.get_header()['phi_width']

  sg = sgtbx.space_group(spacegroup)

  if not (sg.n_ltr() - 1):
    # primitive solution - just return ... something
    return None, None, None, None

  # FIXME need to raise an exception if this is not available!
  m_matrix = indexer.get_indexer_payload('mosflm_orientation_matrix')

  # N.B. in the calculation below I am using the Cambridge frame
  # and Mosflm definitions of X & Y...

  m_elems = []

  for record in m_matrix[:3]:
    record = record.replace('-', ' -')
    for e in map(float, record.split()):
      m_elems.append(e / wavelength)

  mi = matrix.sqr(m_elems)
  m = mi.inverse()

  A = matrix.col(m.elems[0:3])
  B = matrix.col(m.elems[3:6])
  C = matrix.col(m.elems[6:9])

  # now select the images - start with the images that the indexer
  # used for indexing, though can interrogate the FrameProcessor
  # interface of the indexer to put together a completely different
  # list if I like...

  images = []

  for i in indexer.get_indexer_images():
    for j in i:
      if not j in images:
        images.append(j)

  images.sort()

  # now construct the reciprocal-space peak list n.b. should
  # really run this in parallel...

  spots_r = []

  spots_r_j =  { }

  for i in images:
    image = indexer.get_image_name(i)
    dd = Diffdump()
    dd.set_image(image)
    header = dd.readheader()
    phi = header['phi_start'] + 0.5 * header['phi_width']
    pixel = header['pixel']
    wavelength = header['wavelength']
    peaks = locate_maxima(image)

    spots_r_j[i] = []

    for p in peaks:
      x, y, isigma = p

      if isigma < 5.0:
        continue

      xp = pixel[0] * y - beam[0]
      yp = pixel[1] * x - beam[1]

      scale = wavelength * math.sqrt(
          xp * xp + yp * yp + distance * distance)

      X = distance / scale
      X -= 1.0 / wavelength
      Y = - xp / scale
      Z = yp / scale

      S = matrix.col([X, Y, Z])

      rtod = 180.0 / math.pi

      spots_r.append(S.rotate(axis, - phi / rtod))
      spots_r_j[i].append(S.rotate(axis, - phi / rtod))

  # now reindex the reciprocal space spot list and count - n.b. need
  # to transform the Bravais lattice to an assumed spacegroup and hence
  # to a cctbx spacegroup!

  # lists = [spots_r_j[j] for j in spots_r_j]
  lists = []
  lists.append(spots_r)

  for l in lists:

    absent = 0
    present = 0
    total = 0

    for spot in l:
      hkl = (m * spot).elems

      total += 1

      ihkl = map(nint, hkl)

      if math.fabs(hkl[0] - ihkl[0]) > 0.1:
        continue

      if math.fabs(hkl[1] - ihkl[1]) > 0.1:
        continue

      if math.fabs(hkl[2] - ihkl[2]) > 0.1:
        continue

      # now determine if it is absent

      if sg.is_sys_absent(ihkl):
        absent += 1
      else:
        present += 1

    # now perform the analysis on these numbers...

    sd = math.sqrt(absent)

    if total:

      Debug.write('Counts: %d %d %d %.3f' % \
                  (total, present, absent, (absent - 3 * sd) / total))

    else:

      Debug.write('Not enough spots found for analysis')
      return False, None, None, None

    if (absent - 3 * sd) / total < 0.008:
      return False, None, None, None

  # in here need to calculate the new orientation matrix for the
  # primitive basis and reconfigure the indexer - somehow...

  # ok, so the bases are fine, but what I will want to do is reorder them
  # to give the best primitive choice of unit cell...

  sgp = sg.build_derived_group(True, False)
  lattice_p = s2l(sgp.type().number())
  symm = crystal.symmetry(unit_cell = cell,
                          space_group = sgp)

  rdx = symm.change_of_basis_op_to_best_cell()
  symm_new = symm.change_basis(rdx)

  # now apply this to the reciprocal-space orientation matrix mi

  # cb_op = sgtbx.change_of_basis_op(rdx)
  cb_op = rdx
  R = cb_op.c_inv().r().as_rational().as_float().transpose().inverse()
  mi_r = mi * R

  # now re-derive the cell constants, just to be sure

  m_r = mi_r.inverse()
  Ar = matrix.col(m_r.elems[0:3])
  Br = matrix.col(m_r.elems[3:6])
  Cr = matrix.col(m_r.elems[6:9])

  a = math.sqrt(Ar.dot())
  b = math.sqrt(Br.dot())
  c = math.sqrt(Cr.dot())

  rtod = 180.0 / math.pi

  alpha = rtod * Br.angle(Cr)
  beta = rtod * Cr.angle(Ar)
  gamma = rtod * Ar.angle(Br)

  # print '%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f' % \
  # (a, b, c, alpha, beta, gamma)

  cell = uctbx.unit_cell((a, b, c, alpha, beta, gamma))

  amat = [wavelength * e for e in mi_r.elems]
  bmat = matrix.sqr(cell.fractionalization_matrix())
  umat = mi_r * bmat.inverse()

  # yuk! surely I don't need to do this...

  # I do need to do this, and don't call me shirley!

  new_matrix = ['%s\n' % r for r in \
                format_matrix((a, b, c, alpha, beta, gamma),
                              amat, umat.elems).split('\n')]

  # ok - this gives back the right matrix in the right setting - excellent!
  # now need to apply this back at base to the results of the indexer.

  # N.B. same should be applied to the same calculations for the XDS
  # version of this.

  return True, lattice_p, new_matrix, (a, b, c, alpha, beta, gamma)
Ejemplo n.º 6
0
def mosflm_check_indexer_solution(indexer):

    distance = indexer.get_indexer_distance()
    axis = matrix.col([0, 0, 1])
    beam = indexer.get_indexer_beam_centre()
    cell = indexer.get_indexer_cell()
    wavelength = indexer.get_wavelength()

    space_group_number = l2s(indexer.get_indexer_lattice())
    spacegroup = sgtbx.space_group_symbols(space_group_number).hall()
    phi = indexer.get_header()['phi_width']

    sg = sgtbx.space_group(spacegroup)

    if not (sg.n_ltr() - 1):
        # primitive solution - just return ... something
        return None, None, None, None

    # FIXME need to raise an exception if this is not available!
    m_matrix = indexer.get_indexer_payload('mosflm_orientation_matrix')

    # N.B. in the calculation below I am using the Cambridge frame
    # and Mosflm definitions of X & Y...

    m_elems = []

    for record in m_matrix[:3]:
        record = record.replace('-', ' -')
        for e in map(float, record.split()):
            m_elems.append(e / wavelength)

    mi = matrix.sqr(m_elems)
    m = mi.inverse()

    A = matrix.col(m.elems[0:3])
    B = matrix.col(m.elems[3:6])
    C = matrix.col(m.elems[6:9])

    # now select the images - start with the images that the indexer
    # used for indexing, though can interrogate the FrameProcessor
    # interface of the indexer to put together a completely different
    # list if I like...

    images = []

    for i in indexer.get_indexer_images():
        for j in i:
            if not j in images:
                images.append(j)

    images.sort()

    # now construct the reciprocal-space peak list n.b. should
    # really run this in parallel...

    spots_r = []

    spots_r_j = {}

    for i in images:
        image = indexer.get_image_name(i)
        dd = Diffdump()
        dd.set_image(image)
        header = dd.readheader()
        phi = header['phi_start'] + 0.5 * header['phi_width']
        pixel = header['pixel']
        wavelength = header['wavelength']
        peaks = locate_maxima(image)

        spots_r_j[i] = []

        for p in peaks:
            x, y, isigma = p

            if isigma < 5.0:
                continue

            xp = pixel[0] * y - beam[0]
            yp = pixel[1] * x - beam[1]

            scale = wavelength * math.sqrt(xp * xp + yp * yp +
                                           distance * distance)

            X = distance / scale
            X -= 1.0 / wavelength
            Y = -xp / scale
            Z = yp / scale

            S = matrix.col([X, Y, Z])

            rtod = 180.0 / math.pi

            spots_r.append(S.rotate(axis, -phi / rtod))
            spots_r_j[i].append(S.rotate(axis, -phi / rtod))

    # now reindex the reciprocal space spot list and count - n.b. need
    # to transform the Bravais lattice to an assumed spacegroup and hence
    # to a cctbx spacegroup!

    # lists = [spots_r_j[j] for j in spots_r_j]
    lists = []
    lists.append(spots_r)

    for l in lists:

        absent = 0
        present = 0
        total = 0

        for spot in l:
            hkl = (m * spot).elems

            total += 1

            ihkl = map(nint, hkl)

            if math.fabs(hkl[0] - ihkl[0]) > 0.1:
                continue

            if math.fabs(hkl[1] - ihkl[1]) > 0.1:
                continue

            if math.fabs(hkl[2] - ihkl[2]) > 0.1:
                continue

            # now determine if it is absent

            if sg.is_sys_absent(ihkl):
                absent += 1
            else:
                present += 1

        # now perform the analysis on these numbers...

        sd = math.sqrt(absent)

        if total:

            Debug.write('Counts: %d %d %d %.3f' % \
                        (total, present, absent, (absent - 3 * sd) / total))

        else:

            Debug.write('Not enough spots found for analysis')
            return False, None, None, None

        if (absent - 3 * sd) / total < 0.008:
            return False, None, None, None

    # in here need to calculate the new orientation matrix for the
    # primitive basis and reconfigure the indexer - somehow...

    # ok, so the bases are fine, but what I will want to do is reorder them
    # to give the best primitive choice of unit cell...

    sgp = sg.build_derived_group(True, False)
    lattice_p = s2l(sgp.type().number())
    symm = crystal.symmetry(unit_cell=cell, space_group=sgp)

    rdx = symm.change_of_basis_op_to_best_cell()
    symm_new = symm.change_basis(rdx)

    # now apply this to the reciprocal-space orientation matrix mi

    # cb_op = sgtbx.change_of_basis_op(rdx)
    cb_op = rdx
    R = cb_op.c_inv().r().as_rational().as_float().transpose().inverse()
    mi_r = mi * R

    # now re-derive the cell constants, just to be sure

    m_r = mi_r.inverse()
    Ar = matrix.col(m_r.elems[0:3])
    Br = matrix.col(m_r.elems[3:6])
    Cr = matrix.col(m_r.elems[6:9])

    a = math.sqrt(Ar.dot())
    b = math.sqrt(Br.dot())
    c = math.sqrt(Cr.dot())

    rtod = 180.0 / math.pi

    alpha = rtod * Br.angle(Cr)
    beta = rtod * Cr.angle(Ar)
    gamma = rtod * Ar.angle(Br)

    # print '%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f' % \
    # (a, b, c, alpha, beta, gamma)

    cell = uctbx.unit_cell((a, b, c, alpha, beta, gamma))

    amat = [wavelength * e for e in mi_r.elems]
    bmat = matrix.sqr(cell.fractionalization_matrix())
    umat = mi_r * bmat.inverse()

    # yuk! surely I don't need to do this...

    # I do need to do this, and don't call me shirley!

    new_matrix = ['%s\n' % r for r in \
                  format_matrix((a, b, c, alpha, beta, gamma),
                                amat, umat.elems).split('\n')]

    # ok - this gives back the right matrix in the right setting - excellent!
    # now need to apply this back at base to the results of the indexer.

    # N.B. same should be applied to the same calculations for the XDS
    # version of this.

    return True, lattice_p, new_matrix, (a, b, c, alpha, beta, gamma)
Ejemplo n.º 7
0
def mosflm_matrix_centred_to_primitive(lattice, mosflm_a_matrix):
    '''Convert a mosflm orientation matrix from a centred setting to a
  primitive one (i.e. same lattice, but without the centering operations,
  which therefore corresponds to a different basis).'''

    space_group_number = l2s(lattice)
    spacegroup = sgtbx.space_group_symbols(space_group_number).hall()
    sg = sgtbx.space_group(spacegroup)

    rtod = 180.0 / math.pi

    if not (sg.n_ltr() - 1):
        return mosflm_a_matrix

    cell, amat, umat = parse_matrix(mosflm_a_matrix)

    # first derive the wavelength

    mi = matrix.sqr(amat)
    m = mi.inverse()

    A = matrix.col(m.elems[0:3])
    B = matrix.col(m.elems[3:6])
    C = matrix.col(m.elems[6:9])

    a = math.sqrt(A.dot())
    b = math.sqrt(B.dot())
    c = math.sqrt(C.dot())

    alpha = rtod * B.angle(C)
    beta = rtod * C.angle(A)
    gamma = rtod * A.angle(B)

    wavelength = ((cell[0] / a) + (cell[1] / b) + (cell[2] / c)) / 3.0

    # then use this to rescale the A matrix

    mi = matrix.sqr([a / wavelength for a in amat])
    m = mi.inverse()

    sgp = sg.build_derived_group(True, False)
    lattice_p = s2l(sgp.type().number())
    symm = crystal.symmetry(unit_cell=cell, space_group=sgp)

    rdx = symm.change_of_basis_op_to_best_cell()
    symm_new = symm.change_basis(rdx)

    # now apply this to the reciprocal-space orientation matrix mi

    cb_op = rdx
    R = cb_op.c_inv().r().as_rational().as_float().transpose().inverse()
    mi_r = mi * R

    # now re-derive the cell constants, just to be sure

    m_r = mi_r.inverse()
    Ar = matrix.col(m_r.elems[0:3])
    Br = matrix.col(m_r.elems[3:6])
    Cr = matrix.col(m_r.elems[6:9])

    a = math.sqrt(Ar.dot())
    b = math.sqrt(Br.dot())
    c = math.sqrt(Cr.dot())

    alpha = rtod * Br.angle(Cr)
    beta = rtod * Cr.angle(Ar)
    gamma = rtod * Ar.angle(Br)

    cell = uctbx.unit_cell((a, b, c, alpha, beta, gamma))

    amat = [wavelength * e for e in mi_r.elems]
    bmat = matrix.sqr(cell.fractionalization_matrix())
    umat = mi_r * bmat.inverse()

    new_matrix = ['%s\n' % r for r in \
                  format_matrix((a, b, c, alpha, beta, gamma),
                                amat, umat.elems).split('\n')]

    return new_matrix