Source code for schrodinger.application.desmond.packages.msys.atomsel

import os
from past.utils import old_div

import numpy


[docs]class Atomsel(object): ''' Supports alignment of molecular structures ''' __slots__ = ('_ptr', '_ids', '_seltext') ''' atom selection object '''
[docs] def __init__(self, ptr, seltext): ''' don't use directly - use System.atomsel() ''' self._ptr = ptr self._ids = ptr.selectAsArray(seltext) self._seltext = seltext
[docs] def __len__(self): ''' number of selected atoms ''' return len(self._ids)
def __str__(self): return self._seltext def __repr__(self): return "<Atomsel '%s'>" % self._seltext @property def ids(self): ''' ids of selected atoms in the parent system ''' return self._ids @property def system(self): ''' parent system ''' if "SCHRODINGER" not in os.environ: from msys import System else: from schrodinger.application.desmond.packages.msys import System return System(self._ptr)
[docs] def getPositions(self): return self._ptr.getPositions(self._ids)
def _positions(self, other): if isinstance(other, Atomsel): opos = other.getPositions() elif isinstance(other, numpy.ndarray): opos = other if len(other) == self._ptr.atomCount(): opos = other[self._ids] else: opos = other.copy() else: raise TypeError("Require either msys.Atomsel or numpy.ndarray") if len(self) != len(opos): raise ValueError("Size mismatch: self (%d) != other (%d)" % (len(self), len(other))) return opos
[docs] def raw_alignment(self, other): ''' Compute alignment to other object. Compute and return aligned rmsd, and rotational and translational transformations. ''' rpos = self.getPositions() opos = self._positions(other) if len(rpos) == 0: raise RuntimeError( "Empty atom selection '%s' - cannot compute alignment" % self) rcenter = rpos.mean(0) ocenter = opos.mean(0) rpos -= rcenter opos -= ocenter c = numpy.dot(rpos.transpose(), opos) v, s, w_tr = numpy.linalg.svd(c) is_reflection = (numpy.linalg.det(v) * numpy.linalg.det(w_tr)) < 0.0 if is_reflection: s[-1] = -s[-1] v[:, -1] = -v[:, -1] rx = numpy.dot(v, w_tr).transpose() rpos *= rpos opos *= opos E0 = rpos.sum() + opos.sum() msd = old_div((E0 - 2.0 * s.sum()), len(rpos)) msd = max([msd, 0.0]) tx = rcenter - numpy.dot(ocenter, rx) return numpy.sqrt(msd), rx, tx
[docs] def currentRMSD(self, other): ''' compute RMS distance to other object, which may be Atomsel or an array of positions. In either it must be the case that len(other) equals len(self) or len(self.system) ''' dx = self.getPositions() dx -= self._positions(other) dx *= dx return numpy.sqrt(old_div(dx.sum(), len(dx)))
[docs] def alignedRMSD(self, other): ''' Return the aligned rmsd to other. ''' return self.raw_alignment(other)[0]
[docs] def alignCoordinates(self, other): ''' If other is an Atomsel instance, align the coordinates of other's System with self. If other is a numpy array, align the array with self, using corresponding indices. In either case, return the aligned RMSD. ''' dx, rx, tx = self.raw_alignment(other) if isinstance(other, numpy.ndarray): pos = other pos[:] = numpy.dot(pos, rx) pos += tx elif isinstance(other, Atomsel): pos = other.system.getPositions() pos[:] = numpy.dot(pos, rx) pos += tx other.system.setPositions(pos) else: assert False return dx