def setUp(self): self.test_transformations = [] for i in xrange(20): test_transformation = Complete() test_transformation.set_rotation_properties(random.random()*math.pi*2, numpy.random.uniform(-3, 3, 3), random.sample([True, False], 1)[0]) test_transformation.t = numpy.random.uniform(-3, 3, 3) self.test_transformations.append(test_transformation)
def setUp(self): self.test_transformations = [] for i in xrange(20): test_transformation = Complete() test_transformation.set_rotation_properties( random.random() * math.pi * 2, numpy.random.uniform(-3, 3, 3), random.sample([True, False], 1)[0]) test_transformation.t = numpy.random.uniform(-3, 3, 3) self.test_transformations.append(test_transformation)
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 read_from_file(cls, filename): f = file(filename) lines = list(line for line in f if line[0] != '#') f.close() r = [] t = [] for line in lines[:3]: values = list(float(word) for word in line.split()) r.append(values[:3]) t.append(values[3]) transformation = Complete() transformation.r[:] = r transformation.t[:] = t affected_atoms = set(int(word) for word in lines[3].split()) return cls(affected_atoms, transformation)
def initnonstate(self): GLReferentBase.initnonstate(self) self.orientation = Complete() self.set_children([ SpatialReference(prefix="Begin"), SpatialReference(prefix="End") ])
def get_transformation(self, coordinates): """Construct a transformation object""" atom1, atom2 = self.hinge_atoms center = coordinates[atom1] axis = coordinates[atom1] - coordinates[atom2] axis /= np.linalg.norm(axis) angle = np.random.uniform(-self.max_amplitude, self.max_amplitude) return Complete.about_axis(center, angle, axis)
def get_transformation(self, coordinates): """Construct a transformation object""" atom1, atom2 = self.hinge_atoms center = coordinates[atom1] axis = coordinates[atom1] - coordinates[atom2] axis /= numpy.linalg.norm(axis) angle = numpy.random.uniform(-self.max_amplitude, self.max_amplitude) return Complete.about_axis(center, angle, axis)
def __init__(self, affected_atoms, transformation): """Initialize a new MolecularDistortion object Arguments: affected_atoms -- a list of atoms that undergo the transformation transformation -- a transformation object """ self.affected_atoms = affected_atoms self.transformation = Complete.cast(transformation)
def __init__(self, affected_atoms, transformation, molecule=None): self.affected_atoms = affected_atoms self.transformation = Complete() if isinstance(transformation, Rotation): self.transformation.r[:] = transformation.r if isinstance(transformation, Translation): self.transformation.t[:] = transformation.t if molecule is not None: for i in affected_atoms: molecule.coordinates[i] = transformation.vector_apply( molecule.coordinates[i])
def do_test(self, coordinates, masses, expected_is): reference = MolecularDescriptorTV1(coordinates, masses) self.assert_(reference.inversion_symmetric == expected_is) for counter in xrange(3): transformation = Complete() transformation.set_rotation_properties( random.uniform(0, 2*math.pi), numpy.random.uniform(-1, 1, (3,)), False, ) transformation.t = numpy.random.uniform(-5, 5, (3,)) new_coordinates = numpy.array([ transformation.vector_apply(coordinate) for coordinate in coordinates ], float) new_descriptor = MolecularDescriptorTV1(new_coordinates, masses) self.assert_(reference.compare_structure(new_descriptor)) self.assert_(not reference.compare_global_rotation(new_descriptor)) self.assert_(not reference.compare_global_translation(new_descriptor))
def read_from_file(cls, filename): """Construct a MolecularDistortion object from a file""" with open(filename) as f: lines = list(line for line in f if line[0] != '#') r = [] t = [] for line in lines[:3]: values = list(float(word) for word in line.split()) r.append(values[:3]) t.append(values[3]) transformation = Complete(r, t) affected_atoms = set(int(word) for word in lines[3].split()) return cls(affected_atoms, transformation)
def do(self): cache = context.application.cache for node in cache.nodes: transformation = Complete() translated_children = [] for child in node.children: if isinstance(child, GLTransformationMixin) and isinstance(child.transformation, Translation): if child.get_fixed(): translated_children = [] break translated_children.append(child) if len(translated_children) == 0: continue mass, com = compute_center_of_mass(yield_particles(node)) if mass == 0.0: continue transformation.t = com tensor = compute_inertia_tensor(yield_particles(node), com) transformation.r = default_rotation_matrix(tensor) CenterAlignBase.do(self, node, translated_children, transformation)
def get_transformation(self, coordinates): """Construct a transformation object""" atom1, atom2, atom3 = self.hinge_atoms center = coordinates[atom2] a = coordinates[atom1] - coordinates[atom2] b = coordinates[atom3] - coordinates[atom2] axis = np.cross(a, b) norm = np.linalg.norm(axis) if norm < 1e-5: # We suppose that atom3 is part of the affected atoms axis = random_orthonormal(a) else: axis /= np.linalg.norm(axis) angle = np.random.uniform(-self.max_amplitude, self.max_amplitude) return Complete.about_axis(center, angle, axis)
def get_transformation(self, coordinates): """Construct a transformation object""" atom1, atom2, atom3 = self.hinge_atoms center = coordinates[atom2] a = coordinates[atom1] - coordinates[atom2] b = coordinates[atom3] - coordinates[atom2] axis = numpy.cross(a, b) norm = numpy.linalg.norm(axis) if norm < 1e-5: # We suppose that atom3 is part of the affected atoms axis = random_orthonormal(a) else: axis /= numpy.linalg.norm(axis) angle = numpy.random.uniform(-self.max_amplitude, self.max_amplitude) return Complete.about_axis(center, angle, axis)
def do_test(self, coordinates, masses, expected_is): reference = MolecularDescriptorTV1(coordinates, masses) self.assert_(reference.inversion_symmetric == expected_is) for counter in xrange(3): transformation = Complete() transformation.set_rotation_properties( random.uniform(0, 2 * math.pi), numpy.random.uniform(-1, 1, (3, )), False, ) transformation.t = numpy.random.uniform(-5, 5, (3, )) new_coordinates = numpy.array([ transformation.vector_apply(coordinate) for coordinate in coordinates ], float) new_descriptor = MolecularDescriptorTV1(new_coordinates, masses) self.assert_(reference.compare_structure(new_descriptor)) self.assert_(not reference.compare_global_rotation(new_descriptor)) self.assert_( not reference.compare_global_translation(new_descriptor))
def random_dimer(molecule0, molecule1, thresholds, shoot_max): """Create a random dimer. molecule0 and molecule1 are placed in one reference frame at random relative positions. Interatomic distances are above the thresholds. Initially a dimer is created where one interatomic distance approximates the threshold value. Then the molecules are given an additional separation in the range [0, shoot_max]. thresholds has the following format: {frozenset([atom_number1, atom_number2]): distance} """ # apply a random rotation to molecule1 center = numpy.zeros(3, float) angle = numpy.random.uniform(0, 2*numpy.pi) axis = random_unit() rotation = Complete.about_axis(center, angle, axis) cor1 = numpy.dot(molecule1.coordinates, rotation.r) # select a random atom in each molecule atom0 = numpy.random.randint(len(molecule0.numbers)) atom1 = numpy.random.randint(len(molecule1.numbers)) # define a translation of molecule1 that brings both atoms in overlap delta = molecule0.coordinates[atom0] - cor1[atom1] cor1 += delta # define a random direction direction = random_unit() cor1 += 1*direction # move molecule1 along this direction until all intermolecular atomic # distances are above the threshold values threshold_mat = numpy.zeros((len(molecule0.numbers), len(molecule1.numbers)), float) distance_mat = numpy.zeros((len(molecule0.numbers), len(molecule1.numbers)), float) for i1, n1 in enumerate(molecule0.numbers): for i2, n2 in enumerate(molecule1.numbers): threshold = thresholds.get(frozenset([n1, n2])) threshold_mat[i1, i2] = threshold**2 while True: cor1 += 0.1*direction distance_mat[:] = 0 for i in 0, 1, 2: distance_mat += numpy.subtract.outer(molecule0.coordinates[:, i], cor1[:, i])**2 if (distance_mat > threshold_mat).all(): break # translate over a random distance [0, shoot] along the same direction # (if necessary repeat until no overlap is found) while True: cor1 += direction*numpy.random.uniform(0, shoot_max) distance_mat[:] = 0 for i in 0, 1, 2: distance_mat += numpy.subtract.outer(molecule0.coordinates[:, i], cor1[:, i])**2 if (distance_mat > threshold_mat).all(): break # done dimer = Molecule( numpy.concatenate([molecule0.numbers, molecule1.numbers]), numpy.concatenate([molecule0.coordinates, cor1]) ) dimer.direction = direction dimer.atom0 = atom0 dimer.atom1 = atom1 return dimer
class Vector(GLReferentBase): # # State # def initnonstate(self): GLReferentBase.initnonstate(self) self.orientation = Complete() self.set_children([ SpatialReference(prefix="Begin"), SpatialReference(prefix="End") ]) # # Dialog fields (see action EditProperties) # dialog_fields = set([ DialogFieldInfo("Basic", (0, 2), fields.read.VectorLength( label_text="Vector length" )), ]) # # Draw # def draw(self): self.calc_vector_dimensions() context.application.vis_backend.transform(self.orientation) # # Revalidation # def revalidate_total_list(self): if self.gl_active: vb = context.application.vis_backend vb.begin_list(self.total_list) if self.visible: vb.push_name(self.draw_list) vb.push_matrix() self.draw_selection() vb.call_list(self.draw_list) vb.pop_matrix() vb.pop_name() vb.end_list() self.total_list_valid = True def revalidate_draw_list(self): if self.gl_active: GLReferentBase.revalidate_draw_list(self) def revalidate_boundingbox_list(self): if self.gl_active: vb = context.application.vis_backend #print "Compiling selection list (" + str(self.boundingbox_list) + "): " + str(self.name) vb.begin_list(self.boundingbox_list) vb.push_matrix() vb.transform(self.orientation) self.revalidate_bounding_box() self.bounding_box.draw() vb.pop_matrix() vb.end_list() self.boundingbox_list_valid = True # # Frame # def get_bounding_box_in_parent_frame(self): return self.bounding_box.transformed(self.orientation) # # Vector # def shortest_vector_relative_to(self, other): b = self.children[0].translation_relative_to(other) e = self.children[1].translation_relative_to(other) if (b is None) or (e is None): return None else: return self.parent.shortest_vector(e - b) def calc_vector_dimensions(self): relative_translation = self.shortest_vector_relative_to(self.parent) if relative_translation is None: self.length = 0 else: self.length = math.sqrt(numpy.dot(relative_translation, relative_translation)) if self.length > 0: self.orientation.t = self.children[0].translation_relative_to(self.parent) #axis = numpy.cross(relative_translation, numpy.array([1.0, 0.0, 0.0])) c = relative_translation[2] / self.length if c >= 1.0: self.orientation.set_rotation_properties(0, numpy.array([1.0, 0.0, 0.0]), False) elif c <= -1.0: self.orientation.set_rotation_properties(math.pi, numpy.array([1.0, 0.0, 0.0]), False) else: x, y = relative_translation[0], relative_translation[1] if abs(x) < abs(y): signy = {True: 1, False: -1}[y >= 0] a = -signy b = signy * x / y else: signx = {True: 1, False: -1}[x >= 0] a = -signx * y / x b = signx self.orientation.set_rotation_properties(math.acos(c), numpy.array([a, b, 0.0]), False) def define_target(self, reference, new_target): GLReferentBase.define_target(self, reference, new_target) self.invalidate_boundingbox_list() self.invalidate_draw_list() def target_moved(self, reference, target): GLReferentBase.target_moved(self, reference, target) self.invalidate_boundingbox_list() self.invalidate_draw_list()
def random_dimer(molecule0, molecule1, thresholds, shoot_max): """Create a random dimer. molecule0 and molecule1 are placed in one reference frame at random relative positions. Interatomic distances are above the thresholds. Initially a dimer is created where one interatomic distance approximates the threshold value. Then the molecules are given an additional separation in the range [0, shoot_max]. thresholds has the following format: {frozenset([atom_number1, atom_number2]): distance} """ # apply a random rotation to molecule1 center = np.zeros(3, float) angle = np.random.uniform(0, 2 * np.pi) axis = random_unit() rotation = Complete.about_axis(center, angle, axis) cor1 = np.dot(molecule1.coordinates, rotation.r) # select a random atom in each molecule atom0 = np.random.randint(len(molecule0.numbers)) atom1 = np.random.randint(len(molecule1.numbers)) # define a translation of molecule1 that brings both atoms in overlap delta = molecule0.coordinates[atom0] - cor1[atom1] cor1 += delta # define a random direction direction = random_unit() cor1 += 1 * direction # move molecule1 along this direction until all intermolecular atomic # distances are above the threshold values threshold_mat = np.zeros((len(molecule0.numbers), len(molecule1.numbers)), float) distance_mat = np.zeros((len(molecule0.numbers), len(molecule1.numbers)), float) for i1, n1 in enumerate(molecule0.numbers): for i2, n2 in enumerate(molecule1.numbers): threshold = thresholds.get(frozenset([n1, n2])) threshold_mat[i1, i2] = threshold**2 while True: cor1 += 0.1 * direction distance_mat[:] = 0 for i in 0, 1, 2: distance_mat += np.subtract.outer(molecule0.coordinates[:, i], cor1[:, i])**2 if (distance_mat > threshold_mat).all(): break # translate over a random distance [0, shoot] along the same direction # (if necessary repeat until no overlap is found) while True: cor1 += direction * np.random.uniform(0, shoot_max) distance_mat[:] = 0 for i in 0, 1, 2: distance_mat += np.subtract.outer(molecule0.coordinates[:, i], cor1[:, i])**2 if (distance_mat > threshold_mat).all(): break # done dimer = Molecule(np.concatenate([molecule0.numbers, molecule1.numbers]), np.concatenate([molecule0.coordinates, cor1])) dimer.direction = direction dimer.atom0 = atom0 dimer.atom1 = atom1 return dimer
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 compute_transformation(self, connection): transformation = Complete(self.rotation2.r, connection.t) del connection.t return transformation