Example #1
0
    def replace(self, gl_object):
        if not gl_object.get_fixed():
            state = gl_object.__getstate__()
            state.pop("name", None)
            state.pop("transformation", None)
            new = self.get_new(gl_object.transformation.t)

            if(self.current_object == "Fragment"): #fragments are inserted at frames - have no refs
                target_object = new.children[1]
            else:
                target_object = new
            for reference in gl_object.references[::-1]:
                if not reference.check_target(target_object):
                    return
            parent = gl_object.parent
            import copy
            primitive.Add(new, parent)
            if(self.current_object == "Fragment"):
                # rotation
                Bond = context.application.plugins.get_node("Bond")
                if len(gl_object.references) == 1 and isinstance(gl_object.references[0].parent, Bond):
                    bond1 = gl_object.references[0].parent
                    direction1 = bond1.shortest_vector_relative_to(parent)
                    if bond1.children[0].target != gl_object:
                        direction1 *= -1
                    bond2 = new.children[0].references[0].parent
                    direction2 = bond2.shortest_vector_relative_to(parent)
                    if bond2.children[0].target != target_object:
                        direction2 *= -1
                    axis = numpy.cross(direction2, direction1)
                    if numpy.linalg.norm(axis) < 1e-8:
                        axis = random_orthonormal(direction1)
                    angle = compute_angle(direction1, direction2)
                    rotation = Rotation()
                    rotation.set_rotation_properties(angle,axis,False)
                    primitive.Transform(new, rotation)
                else:
                    bond1 = None
                # tranlsation
                translation = Translation()
                pos_old = new.children[1].get_frame_relative_to(parent).t
                pos_new = gl_object.transformation.t
                translation.t = pos_new - pos_old
                primitive.Transform(new, translation)
                if bond1 != None:
                    # bond length
                    old_length = numpy.linalg.norm(direction1)
                    new_length = bonds.get_length(new.children[1].number, bond1.get_neighbor(gl_object).number)
                    translation = Translation()
                    translation.t = -direction1/old_length*(new_length-old_length)
                    primitive.Transform(new, translation)

            for reference in gl_object.references[::-1]:
                reference.set_target(target_object)
            primitive.Delete(gl_object)
            if(self.current_object == "Fragment"):
                primitive.Delete(new.children[0])
                # get rid of frame
                UnframeAbsolute = context.application.plugins.get_action("UnframeAbsolute")
                UnframeAbsolute([new])
Example #2
0
 def add_cell_vector(self,
                     vector,
                     norm_threshold=1e-6,
                     volume_threshold=1e-6):
     active, inactive = self.get_active_inactive()
     if len(active) == 3:
         raise ValueError("The unit cell already has three axes.")
     norm_vector = numpy.linalg.norm(vector)
     if norm_vector < norm_threshold:
         raise ValueError(
             "The norm of the proposed vector must be significantly larger than zero."
         )
     if len(active) == 0:
         # Add the vector
         self.cell[:, 0] = vector
         self.cell_active[0] = True
         # Make sure that the unused vectors are not linearly dependent
         direction = vector / norm_vector
         self.cell[:, 1] = random_orthonormal(direction)
         self.cell[:, 2] = numpy.cross(self.cell[:, 0], self.cell[:, 1])
         # update
         self.update_reciproke()
         return
     a = self.cell[:, active[0]]
     norm_a = numpy.linalg.norm(a)
     if len(active) == 1:
         if 1 - abs(numpy.dot(a, vector) /
                    (norm_vector * norm_a)) < volume_threshold:
             raise ValueError(
                 "Can not add the vector since it is colinear with the existing unit cell axis."
             )
         else:
             # Add the vector
             self.cell[:, inactive[0]] = vector
             self.cell_active[inactive[0]] = True
             # Make sure that the unused vector is not linearly dependent
             self.cell[:, 2] = numpy.cross(self.cell[:, 0], self.cell[:, 1])
             # update
             self.update_reciproke()
             return
     b = self.cell[:, active[1]]
     norm_b = numpy.linalg.norm(b)
     if len(active) == 2:
         backup = self.cell[:, inactive[0]].copy()
         self.cell[:, inactive[0]] = vector
         if abs(
                 numpy.linalg.det(self.cell) /
             (norm_vector * norm_a * norm_b)) < volume_threshold:
             self.cell[:, inactive[0]] = backup
             raise ValueError(
                 "Can not add the vector since it is linearly dependent on the existing unit cell axes."
             )
         else:
             self.cell_active[inactive[0]] = True
             self.update_reciproke()
             return True
Example #3
0
def zmat_to_cart(zmat):
    """Converts a ZMatrix back to cartesian coordinates."""

    numbers = zmat["number"]
    N = len(numbers)
    coordinates = numpy.zeros((N, 3), float)

    # special cases for the first coordinates
    coordinates[1, 2] = zmat["distance"][1]
    if zmat["rel1"][2] == 1:
        sign = -1
    else:
        sign = 1
    coordinates[2,
                2] = zmat["distance"][2] * sign * numpy.cos(zmat["angle"][2])
    coordinates[2,
                1] = zmat["distance"][2] * sign * numpy.sin(zmat["angle"][2])
    coordinates[2] += coordinates[2 - zmat["rel1"][2]]

    ref0 = 3
    for (number, distance, rel1, angle, rel2, dihed, rel3) in zmat[3:]:
        ref1 = ref0 - rel1
        ref2 = ref0 - rel2
        ref3 = ref0 - rel3
        if ref1 < 0: ref1 = 0
        if ref2 < 0: ref2 = 0
        if ref3 < 0: ref3 = 0
        # define frame axes
        origin = coordinates[ref1]
        new_z = coordinates[ref2] - origin
        norm_z = numpy.linalg.norm(new_z)
        if norm_z < 1e-15:
            new_z = numpy.array([0, 0, 1], float)
        else:
            new_z /= numpy.linalg.norm(new_z)
        new_x = coordinates[ref3] - origin
        new_x -= numpy.dot(new_x, new_z) * new_z
        norm_x = numpy.linalg.norm(new_x)
        if norm_x < 1e-15:
            new_x = random_orthonormal(new_z)
        else:
            new_x /= numpy.linalg.norm(new_x)
        # we must make our axes frame left handed due to the poor IUPAC
        # definition of the sign of a dihedral angle.
        new_y = -numpy.cross(new_z, new_x)

        # coordinates of new atom:
        x = distance * numpy.cos(dihed) * numpy.sin(angle)
        y = distance * numpy.sin(dihed) * numpy.sin(angle)
        z = distance * numpy.cos(angle)
        coordinates[ref0] = origin + x * new_x + y * new_y + z * new_z
        # loop
        ref0 += 1

    return numbers, coordinates
Example #4
0
def zmat_to_cart(zmat):
    """Converts a ZMatrix back to cartesian coordinates."""

    numbers = zmat["number"]
    N = len(numbers)
    coordinates = numpy.zeros((N, 3), float)

    # special cases for the first coordinates
    coordinates[1, 2] = zmat["distance"][1]
    if zmat["rel1"][2] == 1:
        sign = -1
    else:
        sign = 1
    coordinates[2, 2] = zmat["distance"][2]*sign*numpy.cos(zmat["angle"][2])
    coordinates[2, 1] = zmat["distance"][2]*sign*numpy.sin(zmat["angle"][2])
    coordinates[2] += coordinates[2-zmat["rel1"][2]]

    ref0 = 3
    for (number, distance, rel1, angle, rel2, dihed, rel3) in zmat[3:]:
        ref1 = ref0 - rel1
        ref2 = ref0 - rel2
        ref3 = ref0 - rel3
        if ref1 < 0: ref1 = 0
        if ref2 < 0: ref2 = 0
        if ref3 < 0: ref3 = 0
        # define frame axes
        origin = coordinates[ref1]
        new_z = coordinates[ref2] - origin
        norm_z = numpy.linalg.norm(new_z)
        if norm_z < 1e-15:
            new_z = numpy.array([0, 0, 1], float)
        else:
            new_z /= numpy.linalg.norm(new_z)
        new_x = coordinates[ref3] - origin
        new_x -= numpy.dot(new_x, new_z)*new_z
        norm_x = numpy.linalg.norm(new_x)
        if norm_x < 1e-15:
            new_x = random_orthonormal(new_z)
        else:
            new_x /= numpy.linalg.norm(new_x)
        # we must make our axes frame left handed due to the poor IUPAC
        # definition of the sign of a dihedral angle.
        new_y = -numpy.cross(new_z, new_x)

        # coordinates of new atom:
        x = distance*numpy.cos(dihed)*numpy.sin(angle)
        y = distance*numpy.sin(dihed)*numpy.sin(angle)
        z = distance*numpy.cos(angle)
        coordinates[ref0] = origin + x*new_x + y*new_y + z*new_z
        # loop
        ref0 += 1

    return numbers, coordinates
Example #5
0
 def get_transformation(self, molecule):
     atom1, atom2, atom3 = self.hinge_atoms
     center = molecule.coordinates[atom2]
     a = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     b = molecule.coordinates[atom3] - molecule.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 rotation_around_center(center, angle, axis)
Example #6
0
 def get_transformation(self, molecule):
     atom1, atom2, atom3 = self.hinge_atoms
     center = molecule.coordinates[atom2]
     a = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     b = molecule.coordinates[atom3] - molecule.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 rotation_around_center(center, angle, axis)
Example #7
0
 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)
Example #8
0
 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)
Example #9
0
 def update_reciproke(self, auto_threshold=1e-6):
     active, inactive = self.get_active_inactive()
     if len(active) == 0:
         self.cell_reciproke = numpy.zeros((3, 3), float)
         return
     elif len(active) == 1:
         temp = copy.deepcopy(self.cell)
         if sum(temp[:,inactive[0]]**2) < auto_threshold:
             temp[:, inactive[0]] = random_orthonormal(temp[:, active[0]])
         if sum(temp[:,inactive[1]]**2) < auto_threshold:
             temp[:, inactive[1]] = numpy.cross(temp[:, inactive[0]], temp[:, active[0]])
     elif len(active) == 2:
         temp = copy.deepcopy(self.cell)
         if sum(temp[:,inactive[0]]**2) < auto_threshold:
             temp[:, inactive[0]] = numpy.cross(temp[:, active[0]], temp[:, active[1]])
     elif len(active) == 3:
         temp = self.cell
     self.cell_reciproke = numpy.transpose(self.cell_active*numpy.transpose(numpy.linalg.inv(temp)))
Example #10
0
 def add_cell_vector(self, vector, norm_threshold=1e-6, volume_threshold=1e-6):
     active, inactive = self.get_active_inactive()
     if len(active) == 3:
         raise ValueError("The unit cell already has three axes.")
     norm_vector = numpy.linalg.norm(vector)
     if norm_vector < norm_threshold:
         raise ValueError("The norm of the proposed vector must be significantly larger than zero.")
     if len(active) == 0:
         # Add the vector
         self.cell[:,0] = vector
         self.cell_active[0] = True
         # Make sure that the unused vectors are not linearly dependent
         direction = vector/norm_vector
         self.cell[:,1] = random_orthonormal(direction)
         self.cell[:,2] = numpy.cross(self.cell[:,0], self.cell[:,1])
         # update
         self.update_reciproke()
         return
     a = self.cell[:,active[0]]
     norm_a = numpy.linalg.norm(a)
     if len(active) == 1:
         if 1 - abs(numpy.dot(a, vector) / (norm_vector * norm_a)) < volume_threshold:
             raise ValueError("Can not add the vector since it is colinear with the existing unit cell axis.")
         else:
             # Add the vector
             self.cell[:,inactive[0]] = vector
             self.cell_active[inactive[0]] = True
             # Make sure that the unused vector is not linearly dependent
             self.cell[:,2] = numpy.cross(self.cell[:,0], self.cell[:,1])
             # update
             self.update_reciproke()
             return
     b = self.cell[:,active[1]]
     norm_b = numpy.linalg.norm(b)
     if len(active) == 2:
         backup = self.cell[:,inactive[0]].copy()
         self.cell[:,inactive[0]] = vector
         if abs(numpy.linalg.det(self.cell) / (norm_vector * norm_a * norm_b)) < volume_threshold:
             self.cell[:,inactive[0]] = backup
             raise ValueError("Can not add the vector since it is linearly dependent on the existing unit cell axes.")
         else:
             self.cell_active[inactive[0]] = True
             self.update_reciproke()
             return True
Example #11
0
 def update_reciproke(self, auto_threshold=1e-6):
     active, inactive = self.get_active_inactive()
     if len(active) == 0:
         self.cell_reciproke = numpy.zeros((3, 3), float)
         return
     elif len(active) == 1:
         temp = copy.deepcopy(self.cell)
         if sum(temp[:, inactive[0]]**2) < auto_threshold:
             temp[:, inactive[0]] = random_orthonormal(temp[:, active[0]])
         if sum(temp[:, inactive[1]]**2) < auto_threshold:
             temp[:, inactive[1]] = numpy.cross(temp[:, inactive[0]],
                                                temp[:, active[0]])
     elif len(active) == 2:
         temp = copy.deepcopy(self.cell)
         if sum(temp[:, inactive[0]]**2) < auto_threshold:
             temp[:, inactive[0]] = numpy.cross(temp[:, active[0]],
                                                temp[:, active[1]])
     elif len(active) == 3:
         temp = self.cell
     self.cell_reciproke = numpy.transpose(
         self.cell_active * numpy.transpose(numpy.linalg.inv(temp)))
Example #12
0
        def add_hydrogens(atom):
            existing_bonds = list(atom.yield_bonds())
            num_bonds = len(existing_bonds)
            bond_length = bonds.get_length(atom.number, 1, BOND_SINGLE)

            if num_bonds == 0:
                H = Atom(name="auto H", number=1)
                H.transformation.t = atom.transformation.t + numpy.array([0,bond_length,0])
                primitive.Add(H, atom.parent)
                bond = Bond(name="aut H bond", targets=[atom, H])
                primitive.Add(bond, atom.parent)
                existing_bonds.append(bond)
                num_bonds = 1

            used_valence = 0
            oposite_direction = numpy.zeros(3, float)
            for bond in existing_bonds:
                shortest_vector = bond.shortest_vector_relative_to(atom.parent)
                if bond.children[1].target == atom:
                    shortest_vector *= -1
                oposite_direction -= shortest_vector

                if bond.bond_type == BOND_SINGLE:
                    used_valence += 1
                elif bond.bond_type == BOND_DOUBLE:
                    used_valence += 2
                elif bond.bond_type == BOND_TRIPLE:
                    used_valence += 3

            oposite_direction /= numpy.linalg.norm(oposite_direction)

            num_hydrogens = valence_el(atom.number) - 2*lone_pairs(atom.number) - used_valence
            if num_hydrogens <= 0:
                return

            hybride_count = num_hydrogens + lone_pairs(atom.number) + num_bonds - (used_valence - num_bonds)
            num_sites = num_hydrogens + lone_pairs(atom.number)
            rotation = Rotation()
            rotation.set_rotation_properties(2*math.pi / float(num_sites), oposite_direction, False)
            opening_key = (hybride_count, num_sites)
            opening_angle = self.opening_angles.get(opening_key)
            if opening_angle is None:
                return

            if num_bonds == 1:
                first_bond = existing_bonds[0]
                other_atom = first_bond.children[0].target
                if other_atom == atom:
                    other_atom = first_bond.children[1].target
                other_bonds = [bond for bond in other_atom.yield_bonds() if bond != first_bond]
                if len(other_bonds) > 0:
                    normal = other_bonds[0].shortest_vector_relative_to(atom.parent)
                    normal -= numpy.dot(normal, oposite_direction) * oposite_direction
                    normal /= numpy.linalg.norm(normal)
                    if other_bonds[0].children[0].target == other_atom:
                        normal *= -1
                else:
                    normal = random_orthonormal(oposite_direction)
            elif num_bonds == 2:
                normal = numpy.cross(oposite_direction, existing_bonds[0].shortest_vector_relative_to(atom.parent))
                normal /= numpy.linalg.norm(normal)
            elif num_bonds == 3:
                normal = random_orthonormal(oposite_direction)
            else:
                return

            h_pos = bond_length*(oposite_direction*math.cos(opening_angle) + normal*math.sin(opening_angle))

            for i in range(num_hydrogens):
                H = Atom(name="auto H", number=1)
                H.transformation.t = atom.transformation.t + h_pos
                primitive.Add(H, atom.parent)
                bond = Bond(name="aut H bond", targets=[atom, H])
                primitive.Add(bond, atom.parent)
                h_pos = rotation.vector_apply(h_pos)