def calculateFromAsymmetricUnitAtoms(self, atom_iterator, space_group, cell=None): if cell is None: cell = self.cell st = cartesianCoordinateSymmetryTransformations(cell, space_group) it = ((atom_id, element, tr(position), 0., occupancy) for atom_id, element, position, adp, occupancy in atom_iterator for tr in st) self.calculateFromUnitCellAtoms(it, cell)
def symmetryTransformations(self): """ :returns: a list of transformation objects representing the symmetry operations that must be applied to the asymmetric unit in order to obtain the contents of the unit cell :rtype: list of Scientific.Geometry.Transformation.Transformation """ return cartesianCoordinateSymmetryTransformations( self.cell, self.space_group)
def test_basis(self): for params, rb, sg, nb in datasets: cell = UnitCell(*params) sg = space_groups[sg] trs = cartesianCoordinateSymmetryTransformations(cell, sg) basis = symmetricTensorBasis(cell, sg) assert len(basis) == nb for t in basis: for tr in trs: t_rot = t.applyRotationMatrix(tr.tensor.array) assert largestAbsoluteElement((t_rot - t).array) < 1.e-12
def _countContacts(self): sg = self.re.reflection_set.space_group cell = self.re.reflection_set.cell symops = cartesianCoordinateSymmetryTransformations(cell, sg) unit_cell = [] for tr in symops: for index in range(self.re.natoms): unit_cell.append((index, tr(Vector(self.re.positions[index])))) self.contacts = N.zeros((self.re.natoms), N.Int) for i in range(self.re.natoms): index1, p1 = unit_cell[i] for j in range(i + 1, len(unit_cell)): index2, p2 = unit_cell[j] r = cell.minimumImageDistanceVector(p1, p2).length() if r < 0.7: self.contacts[index1] += 1 self.contacts[index2] += 1
def test_symmetry_ops(self): for params, rb, sg in datasets: cell = UnitCell(*params) sg = space_groups[sg] transformations = cartesianCoordinateSymmetryTransformations(cell, sg) for t in transformations: # Check that the transformation is a rotation-translation. error = N.absolute(N.multiply.reduce(t.tensor.eigenvalues())-1.) self.assert_(error < 1.e-12) # Check that applying the transformation N times (where N is # the number of symmetry operations) yields a transformation # without rotation. ntimes = t for i in range(1, len(sg)): ntimes = ntimes*t self.assert_(largestAbsoluteElement( (ntimes.tensor-delta).array) < 1.e-12)
def calculateFromAsymmetricUnitAtoms(self, atom_iterator, space_group, cell=None): """ :param atom_iterator: an iterator or sequence that yields for each atom in the asymmetric unit a tuple of (atom_id, chemical element, position vector, position fluctuation, occupancy). The position fluctuation can be a symmetric tensor (ADP tensor) or a scalar (implicitly multiplied by the unit tensor). :param space_group: the space group of the crystal :type space_group: CDTK.SpaceGroups.SpaceGroup :type atom_iterator: iterable :param cell: a unit cell, which defaults to the unit cell for which the map object is defined. If a different unit cell is given, the map is calculated for this cell in fractional coordinates and converted to Cartesian coordinates using the unit cell of the map object. This is meaningful only if the two unit cells are very similar, such as for unit cells corresponding to different steps in a constant-pressure Molecular Dynamics simulation. :type cell: CDTK.Crystal.UnitCell """ if cell is None: cell = self.cell st = cartesianCoordinateSymmetryTransformations(cell, space_group) def check(adp): # Only isotropic B factors are handled for now if not isinstance(adp, float): raise NotImplementedError("Symmetry transformation of ADPs" " not yet implemented") return adp it = ((atom_id, element, tr(position), check(adp), occupancy) for atom_id, element, position, adp, occupancy in atom_iterator for tr in st) self.calculateFromUnitCellAtoms(it, cell)
class AtomSubsetRefinementEngine(RefinementEngine): """ RefinementEngine for an atom subset An AtomSubsetRefinementEngine works as a driver for an all-atom RefinementEngine. It works on a subset of the atoms (e.g. the C-alpha atoms of a protein). Every change of the parameters of these atoms is extended to the remaining atoms by an interpolation scheme. The idea behind this approach is that both atom displacements and atomic ADPs are slowly-varying functions of position when considered at low resolutions. A typical refinement protocol based on this class would be the following: 1. Create a RefinementEngine for the all-atom refinement task. 2. Create an AtomSubsetRefinementEngine for a suitable atom subset. 3. Refine at the subset level. 4. Refine at the all-atom level using the all-atom RefinementEngine. The interpolation scheme for atom displacements and atomic ADPs assigns values to each atom that is not in the subset based on the values for the atoms that are in the subset as well as their images constructed by applying the symmetry operations of the space group. The weight of each atom in the interpolation is a function of its minimum-image distance vector from the target atom. The default weights are given by the inverse of the squared length of the distance vector. """ def __init__(self, all_atom_refinement_engine, subset_atom_ids, distance_power=4): """ :param all_atom_refinement_engine: the underlying all-atom refinement engine :type all_atom_refinement_engine: CDTK.Refinement.RefinementEngine :param subset_atom_ids: the ids of the atoms that are part of the subset to be used in refinement :type subset_atom_ids: sequence :param distance_power: the power of the length of the distance vector in the calculation of the weight :type distance_power: int """ assert isinstance(all_atom_refinement_engine, RefinementEngine) self.re = all_atom_refinement_engine self.ids = subset_atom_ids self.power = distance_power try: self.aa_indices = [self.re.id_dict[id] for id in self.ids] except KeyError, e: raise ValueError("Atom %s is not used in refinement engine %s" % (str(e.args[0]), str(all_atom_refinement_engine))) self.natoms = len(self.ids) self.id_dict = dict(zip(self.ids, range(self.natoms))) self.positions = N.take(self.re.positions, self.aa_indices) self.position_updates = 0. * self.positions self.adps = N.take(self.re.adps, self.aa_indices) self.occupancies = N.take(self.re.occupancies, self.aa_indices) sg = self.re.reflection_set.space_group cell = self.re.reflection_set.cell symops = cartesianCoordinateSymmetryTransformations(cell, sg) unit_cell_subset = [] for id in self.ids: for tr in symops: index = self.id_dict[id] rm = tr.tensor.array rmt = symmetricTensorRotationMatrix(rm) unit_cell_subset.append( (index, rm, rmt, tr(Vector(self.positions[index])))) self.position_interpolation = N.zeros( (self.re.natoms, 3, self.natoms, 3), N.Float) self.adp_interpolation = N.zeros((self.re.natoms, 6, self.natoms, 6), N.Float) for i in range(self.re.natoms): if i in self.aa_indices: si = self.aa_indices.index(i) for k in range(3): self.position_interpolation[i, k, si, k] = 1. for k in range(6): self.adp_interpolation[i, k, si, k] = 1. else: nb = [] r = Vector(self.re.positions[i]) for sindex, rot_v, rot_adp, position in unit_cell_subset: d = cell.minimumImageDistanceVector(r, position) nb.append((d, sindex, rot_v, rot_adp)) self._interpolate(i, nb) self.position_interpolation.shape = (3 * self.re.natoms, 3 * self.natoms) self.adp_interpolation.shape = (6 * self.re.natoms, 6 * self.natoms) self.state_valid = False