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
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
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
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)
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)
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)
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