def superpositionFit(confs): """ :param confs: the weight, reference position, and alternate position for each atom :type confs: sequence of (float, Vector, Vector) :returns: the quaternion representing the rotation, the center of mass in the reference configuration, the center of mass in the alternate configuraton, and the RMS distance after the optimal superposition """ w_sum = 0. wr_sum = N.zeros((3,), N.Float) for w, r_ref, r in confs: w_sum += w wr_sum += w*r_ref.array ref_cms = wr_sum/w_sum pos = N.zeros((3,), N.Float) possq = 0. cross = N.zeros((3, 3), N.Float) for w, r_ref, r in confs: w = w/w_sum r_ref = r_ref.array-ref_cms r = r.array pos = pos + w*r possq = possq + w*N.add.reduce(r*r) \ + w*N.add.reduce(r_ref*r_ref) cross = cross + w*r[:, N.NewAxis]*r_ref[N.NewAxis, :] k = N.zeros((4, 4), N.Float) k[0, 0] = -cross[0, 0]-cross[1, 1]-cross[2, 2] k[0, 1] = cross[1, 2]-cross[2, 1] k[0, 2] = cross[2, 0]-cross[0, 2] k[0, 3] = cross[0, 1]-cross[1, 0] k[1, 1] = -cross[0, 0]+cross[1, 1]+cross[2, 2] k[1, 2] = -cross[0, 1]-cross[1, 0] k[1, 3] = -cross[0, 2]-cross[2, 0] k[2, 2] = cross[0, 0]-cross[1, 1]+cross[2, 2] k[2, 3] = -cross[1, 2]-cross[2, 1] k[3, 3] = cross[0, 0]+cross[1, 1]-cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2.*k for i in range(4): k[i, i] = k[i, i] + possq - N.add.reduce(pos*pos) from Scientific import LA e, v = LA.eigenvectors(k) i = N.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = N.sqrt(e[i]) from Scientific.Geometry import Quaternion return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def superpositionFit(confs): """ :param confs: the weight, reference position, and alternate position for each atom :type confs: sequence of (float, Vector, Vector) :returns: the quaternion representing the rotation, the center of mass in the reference configuration, the center of mass in the alternate configuraton, and the RMS distance after the optimal superposition """ w_sum = 0. wr_sum = N.zeros((3, ), N.Float) for w, r_ref, r in confs: w_sum += w wr_sum += w * r_ref.array ref_cms = wr_sum / w_sum pos = N.zeros((3, ), N.Float) possq = 0. cross = N.zeros((3, 3), N.Float) for w, r_ref, r in confs: w = w / w_sum r_ref = r_ref.array - ref_cms r = r.array pos = pos + w * r possq = possq + w*N.add.reduce(r*r) \ + w*N.add.reduce(r_ref*r_ref) cross = cross + w * r[:, N.NewAxis] * r_ref[N.NewAxis, :] k = N.zeros((4, 4), N.Float) k[0, 0] = -cross[0, 0] - cross[1, 1] - cross[2, 2] k[0, 1] = cross[1, 2] - cross[2, 1] k[0, 2] = cross[2, 0] - cross[0, 2] k[0, 3] = cross[0, 1] - cross[1, 0] k[1, 1] = -cross[0, 0] + cross[1, 1] + cross[2, 2] k[1, 2] = -cross[0, 1] - cross[1, 0] k[1, 3] = -cross[0, 2] - cross[2, 0] k[2, 2] = cross[0, 0] - cross[1, 1] + cross[2, 2] k[2, 3] = -cross[1, 2] - cross[2, 1] k[3, 3] = cross[0, 0] + cross[1, 1] - cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2. * k for i in range(4): k[i, i] = k[i, i] + possq - N.add.reduce(pos * pos) from Scientific import LA e, v = LA.eigenvectors(k) i = N.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = N.sqrt(e[i]) from Scientific.Geometry import Quaternion return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def findTransformationAsQuaternion(self, conf1, conf2=None): universe = self.universe() if conf1.universe != universe: raise ValueError("conformation is for a different universe") if conf2 is None: conf1, conf2 = conf2, conf1 else: if conf2.universe != universe: raise ValueError("conformation is for a different universe") ref = conf1 conf = conf2 weights = universe.masses() weights = weights / self.mass() ref_cms = self.centerOfMass(ref).array pos = Numeric.zeros((3, ), Numeric.Float) possq = 0. cross = Numeric.zeros((3, 3), Numeric.Float) for a in self.atomList(): r = a.position(conf).array r_ref = a.position(ref).array - ref_cms w = weights[a] pos = pos + w * r possq = possq + w*Numeric.add.reduce(r*r) \ + w*Numeric.add.reduce(r_ref*r_ref) cross = cross + w * r[:, Numeric.NewAxis] * r_ref[Numeric.NewAxis, :] k = Numeric.zeros((4, 4), Numeric.Float) k[0, 0] = -cross[0, 0] - cross[1, 1] - cross[2, 2] k[0, 1] = cross[1, 2] - cross[2, 1] k[0, 2] = cross[2, 0] - cross[0, 2] k[0, 3] = cross[0, 1] - cross[1, 0] k[1, 1] = -cross[0, 0] + cross[1, 1] + cross[2, 2] k[1, 2] = -cross[0, 1] - cross[1, 0] k[1, 3] = -cross[0, 2] - cross[2, 0] k[2, 2] = cross[0, 0] - cross[1, 1] + cross[2, 2] k[2, 3] = -cross[1, 2] - cross[2, 1] k[3, 3] = cross[0, 0] + cross[1, 1] - cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2. * k for i in range(4): k[i, i] = k[i, i] + possq - Numeric.add.reduce(pos * pos) from Scientific import LA e, v = LA.eigenvectors(k) i = Numeric.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = Numeric.sqrt(e[i]) return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def findTransformationAsQuaternion(self, conf1, conf2 = None): universe = self.universe() if conf1.universe != universe: raise ValueError("conformation is for a different universe") if conf2 is None: conf1, conf2 = conf2, conf1 else: if conf2.universe != universe: raise ValueError("conformation is for a different universe") ref = conf1 conf = conf2 weights = universe.masses() weights = weights/self.mass() ref_cms = self.centerOfMass(ref).array pos = Numeric.zeros((3,), Numeric.Float) possq = 0. cross = Numeric.zeros((3, 3), Numeric.Float) for a in self.atomList(): r = a.position(conf).array r_ref = a.position(ref).array-ref_cms w = weights[a] pos = pos + w*r possq = possq + w*Numeric.add.reduce(r*r) \ + w*Numeric.add.reduce(r_ref*r_ref) cross = cross + w*r[:, Numeric.NewAxis]*r_ref[Numeric.NewAxis, :] k = Numeric.zeros((4, 4), Numeric.Float) k[0, 0] = -cross[0, 0]-cross[1, 1]-cross[2, 2] k[0, 1] = cross[1, 2]-cross[2, 1] k[0, 2] = cross[2, 0]-cross[0, 2] k[0, 3] = cross[0, 1]-cross[1, 0] k[1, 1] = -cross[0, 0]+cross[1, 1]+cross[2, 2] k[1, 2] = -cross[0, 1]-cross[1, 0] k[1, 3] = -cross[0, 2]-cross[2, 0] k[2, 2] = cross[0, 0]-cross[1, 1]+cross[2, 2] k[2, 3] = -cross[1, 2]-cross[2, 1] k[3, 3] = cross[0, 0]+cross[1, 1]-cross[2, 2] for i in range(1, 4): for j in range(i): k[i, j] = k[j, i] k = 2.*k for i in range(4): k[i, i] = k[i, i] + possq - Numeric.add.reduce(pos*pos) from Scientific import LA e, v = LA.eigenvectors(k) i = Numeric.argmin(e) v = v[i] if v[0] < 0: v = -v if e[i] <= 0.: rms = 0. else: rms = Numeric.sqrt(e[i]) return Quaternion.Quaternion(v), Vector(ref_cms), \ Vector(pos), rms
def __init__(self, trajectory, object, first=0, last=None, skip=1, reference = None): self.trajectory = trajectory universe = trajectory.universe if last is None: last = len(trajectory) first_conf = trajectory.configuration[first] offset = universe.contiguousObjectOffset([object], first_conf, True) if reference is None: reference = first_conf reference = universe.contiguousObjectConfiguration([object], reference) steps = (last-first+skip-1)/skip mass = object.mass() ref_cms = object.centerOfMass(reference) atoms = object.atomList() possq = N.zeros((steps,), N.Float) cross = N.zeros((steps, 3, 3), N.Float) rcms = N.zeros((steps, 3), N.Float) # cms of the CONTIGUOUS object made of CONTINUOUS atom trajectories for a in atoms: r = trajectory.readParticleTrajectory(a, first, last, skip, "box_coordinates").array w = a._mass/mass N.add(rcms, w*r, rcms) if offset is not None: N.add(rcms, w*offset[a].array, rcms) # relative coords of the CONTIGUOUS reference r_ref = N.zeros((len(atoms), 3), N.Float) for a in range(len(atoms)): r_ref[a] = atoms[a].position(reference).array - ref_cms.array # main loop: storing data needed to fill M matrix for a in range(len(atoms)): r = trajectory.readParticleTrajectory(atoms[a], first, last, skip, "box_coordinates").array r = r - rcms # (a-b)**2 != a**2 - b**2 if offset is not None: N.add(r, offset[atoms[a]].array,r) trajectory._boxTransformation(r, r) w = atoms[a]._mass/mass N.add(possq, w*N.add.reduce(r*r, -1), possq) N.add(possq, w*N.add.reduce(r_ref[a]*r_ref[a],-1), possq) N.add(cross, w*r[:,:,N.NewAxis]*r_ref[N.NewAxis, a,:],cross) self.trajectory._boxTransformation(rcms, rcms) # filling matrix M (formula no 40) k = N.zeros((steps, 4, 4), N.Float) k[:, 0, 0] = -cross[:, 0, 0]-cross[:, 1, 1]-cross[:, 2, 2] k[:, 0, 1] = cross[:, 1, 2]-cross[:, 2, 1] k[:, 0, 2] = cross[:, 2, 0]-cross[:, 0, 2] k[:, 0, 3] = cross[:, 0, 1]-cross[:, 1, 0] k[:, 1, 1] = -cross[:, 0, 0]+cross[:, 1, 1]+cross[:, 2, 2] k[:, 1, 2] = -cross[:, 0, 1]-cross[:, 1, 0] k[:, 1, 3] = -cross[:, 0, 2]-cross[:, 2, 0] k[:, 2, 2] = cross[:, 0, 0]-cross[:, 1, 1]+cross[:, 2, 2] k[:, 2, 3] = -cross[:, 1, 2]-cross[:, 2, 1] k[:, 3, 3] = cross[:, 0, 0]+cross[:, 1, 1]-cross[:, 2, 2] del cross for i in range(1, 4): for j in range(i): k[:, i, j] = k[:, j, i] N.multiply(k, 2., k) for i in range(4): N.add(k[:,i,i], possq, k[:,i,i]) del possq quaternions = N.zeros((steps, 4), N.Float) fit = N.zeros((steps,), N.Float) from Scientific.LA import eigenvectors for i in range(steps): e, v = eigenvectors(k[i]) j = N.argmin(e) if e[j] < 0.: fit[i] = 0. else: fit[i] = N.sqrt(e[j]) if v[j,0] < 0.: quaternions[i] = -v[j] # eliminate jumps else: quaternions[i] = v[j] self.fit = fit self.cms = rcms self.quaternions = quaternions