def test_superpose(self): # create a few test sets with random data points, including degenerate # situations. (e.g. one point, two points, linear points) references = [ # a list of 2-tuples: (points, degenerate) (numpy.random.normal(0, 5, (n, 3)), False) for n in xrange(4, 40) ] + [ #(numpy.array([[0,0,1]], float), True), #(numpy.array([[0,0,0],[0,0,1]], float), True), #(numpy.array([[0,0,0],[0,0,1],[0,0,2]], float), True), #(numpy.array([[0,0,0],[0,0,1],[0,0,2],[0,0,4]], float), True), #(numpy.random.normal(0, 5, (3, 3)), True) ] # Do a random transformation on the points randomized = [] for points, degenerate in references: #points[:] -= points.mean(axis=0) axis = random_unit(3) angle = numpy.random.uniform(0, numpy.pi * 2) transformation = Complete() transformation.set_rotation_properties(angle, axis, False) transformation.t[:] = numpy.random.normal(0, 5, 3) randomized.append( (numpy.array([transformation.vector_apply(p) for p in points]), transformation)) for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized): check_transf = superpose(ref_points, tr_points) # check whether the rotation matrix is orthogonal self.assertArraysAlmostEqual( numpy.dot(check_transf.r, check_transf.r.transpose()), numpy.identity(3, float), 1e-5) # first check whether check_transf brings the tr_points back to the ref_points check_points = numpy.dot( tr_points, check_transf.r.transpose()) + check_transf.t self.assertArraysAlmostEqual(ref_points, check_points, 1e-5, doabs=True) if not degenerate: # if the set of points is not degenerate, check whether transf and check_transf # are each other inverses tmp = Complete() tmp.apply_before(transf) tmp.apply_before(check_transf) self.assertArraysAlmostEqual( numpy.dot(transf.r, check_transf.r), numpy.identity(3, float), 1e-5) self.assertArrayAlmostZero(tmp.t, 1e-5) # Add some distortion to the transformed points randomized = [] for tr_points, transf in randomized: tr_points[:] += numpy.random.normal(0, 1.0, len(tr_points)) # Do a blind test for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized): superpose(ref_points, tr_points)
def test_superpose(self): # create a few test sets with random data points, including degenerate # situations. (e.g. one point, two points, linear points) references = [ # a list of 2-tuples: (points, degenerate) (numpy.random.normal(0, 5, (n, 3)), False) for n in xrange(4, 40) ] + [ #(numpy.array([[0,0,1]], float), True), #(numpy.array([[0,0,0],[0,0,1]], float), True), #(numpy.array([[0,0,0],[0,0,1],[0,0,2]], float), True), #(numpy.array([[0,0,0],[0,0,1],[0,0,2],[0,0,4]], float), True), #(numpy.random.normal(0, 5, (3, 3)), True) ] # Do a random transformation on the points randomized = [] for points, degenerate in references: #points[:] -= points.mean(axis=0) axis = random_unit(3) angle = numpy.random.uniform(0, numpy.pi*2) transformation = Complete() transformation.set_rotation_properties(angle, axis, False) transformation.t[:] = numpy.random.normal(0, 5, 3) randomized.append(( numpy.array([transformation.vector_apply(p) for p in points]), transformation )) for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized): check_transf = superpose(ref_points, tr_points) # check whether the rotation matrix is orthogonal self.assertArraysAlmostEqual(numpy.dot(check_transf.r, check_transf.r.transpose()), numpy.identity(3, float), 1e-5) # first check whether check_transf brings the tr_points back to the ref_points check_points = numpy.dot(tr_points, check_transf.r.transpose()) + check_transf.t self.assertArraysAlmostEqual(ref_points, check_points, 1e-5, doabs=True) if not degenerate: # if the set of points is not degenerate, check whether transf and check_transf # are each other inverses tmp = Complete() tmp.apply_before(transf) tmp.apply_before(check_transf) self.assertArraysAlmostEqual(numpy.dot(transf.r, check_transf.r), numpy.identity(3, float), 1e-5) self.assertArrayAlmostZero(tmp.t, 1e-5) # Add some distortion to the transformed points randomized = [] for tr_points, transf in randomized: tr_points[:] += numpy.random.normal(0, 1.0, len(tr_points)) # Do a blind test for (ref_points, degenerate), (tr_points, transf) in zip(references, randomized): superpose(ref_points, tr_points)
def coords_to_zeobuilder(org_coords, opt_coords, atoms, parent, graph=None): if graph == None: atomgroups = [numpy.arange(len(atoms))] else: atomgroups = graph.independent_nodes for group in atomgroups: group_org = org_coords[group] group_opt = opt_coords[group] # Transform the guessed geometry as to overlap with the original geometry transf = superpose(group_org, group_opt) group_opt = numpy.dot(group_opt, transf.r.transpose()) + transf.t # Put coordinates of guessed geometry back into Zeobuilder model for i,atomindex in enumerate(group): translation = Translation() atom = graph.molecule.atoms[atomindex] # Make sure atoms in subframes are treated properly transf = atom.parent.get_frame_relative_to(parent) org_pos = atom.transformation.t opt_pos = transf.vector_apply_inverse(group_opt[i]) translation = Translation() translation.t = opt_pos - org_pos primitive.Transform(atom, translation)
def coords_to_zeobuilder(org_coords, opt_coords, atoms, parent): # Transform the guessed geometry as to overlap with the original geometry transf = superpose(org_coords, opt_coords) opt_coords = numpy.dot(opt_coords, transf.r.transpose()) + transf.t # Put coordinates of guess geometry back into Zeobuilder model for i in xrange(len(atoms)): translation = Translation() atom = atoms[i] # Make sure atoms in subframes are treated properly transf = atom.parent.get_frame_relative_to(parent) org_pos = atom.transformation.t opt_pos = transf.vector_apply_inverse(opt_coords[i]) translation.t = opt_pos - org_pos primitive.Transform(atom, translation)
def fit_geometry(ref_coordinates, mtr, mtw, do_geom=False, do_transform=False, weights=None): """Fits a trajectorie of cartesian coordinates to a reference geometry This is the well-known rmsd fit typically performed on a trajectory after a long solute/solvent simulation (on the solute). It is based on the Kabsch algorithm: http://en.wikipedia.org/wiki/Kabsch_algorithm http://dx.doi.org/10.1107/S0567739476001873 This implementation has a few features that are sorely missing in comparable software tools. One can optionally use the atomic masses as weights, which is a better approximation when one is interested in removing globale linear and angular momentum. Arguments: ref_coordinates -- the reference coordinates to fit to (Nx3 array) mtr -- A MultiTracksReader that iterates of the frames of the trajectory. mtw -- A MultiTracksWriter that writes out the rmsd, and optionally the rotated and translated geometry (do_geom=True), and the rotation matrix and translation vector. (do_transform=True) do_geom -- When True, the rotated and translated geometry is also written out do_transform -- When True, the rotation matrix and translation vector are also written weights -- The weights to be used in the Kabsch algorithm """ for frame in mtr: transform = superpose(ref_coordinates, frame[0], weights) new_coordinates = numpy.dot(frame[0], transform.r.transpose()) + transform.t rmsd = ((new_coordinates - ref_coordinates)**2).mean() row = [rmsd] if do_geom: row.append(new_coordinates) if do_transform: row.append(transform.t) row.append(transform.r) mtw.dump_row(tuple(row)) mtw.finish()