Ejemplo n.º 1
0
def set_dihedral(a1, a2, a3, a4, theta, adjustmol=True):
    """ Set the twist angle of atoms a1 and a4 around the central bond a2-a3. The atoms will be
    adjusted along the
    gradient of the angle.
    If ``adjustmol`` is True and the topology is unambiguous, then the entire molecule's positions
    will be modified as well

    Args:
        a1,a2,a3,a4 (mdt.Atom): atoms to adjust
        theta (u.Scalar[angle]): new angle to set
        adjustmol (bool): Adjust all atoms on either side of this bond?
    """
    # TODO: deal with co-linear a1/a4, a2, a3 - the angle is ill-defined \
    #      (should just an arbitrary axis normal to the central bond)
    current = dihedral(a1, a2, a3, a4)
    rotation = sub_angles(theta, current)
    if abs(rotation) < 1.0e-6: return

    axis = a2.position - a3.position
    if not adjustmol:
        rotmat_l = external.transformations.rotation_matrix(
            -rotation / 2.0, axis, a3.position)
        rotmat_r = external.transformations.rotation_matrix(
            rotation / 2.0, axis, a3.position)

        a1.position = apply_4x4_transform(rotmat_l, a1.position)
        a4.position = apply_4x4_transform(rotmat_r, a4.position)

    else:
        mol = a2.molecule
        indices, sign = _get_fragment_indices(mol, a3, a2)
        rotmat = external.transformations.rotation_matrix(
            rotation, axis * sign, a3.position)
        mol.positions[indices] = apply_4x4_transform(rotmat,
                                                     mol.positions[indices])
Ejemplo n.º 2
0
def set_angle(a1, a2, a3, theta, adjustmol=True):
    """ Set the angle between bonds a1-a2 and a3-a2. The atoms will be adjusted along the
    gradient of the angle.
    If ``adjustmol`` is True and the topology is unambiguous, then the entire molecule's positions
    will be modified as well

    Args:
        a1,a2,a3 (mdt.Atom): atoms to adjust
        theta (u.Scalar[angle]): new angle to set
        adjustmol (bool): Adjust all atoms on either side of this bond?
    """
    # TODO: deal with co-linear a1, a2, a3 - the rotation axis is ill-defined in this case \
    #      (require an axis to be specified)
    # TODO: weakly cache the rotation axis so that users can set angle to 0 or 180 without losing the axis
    current = angle(a1, a2, a3)
    rotation = sub_angles(current, theta)
    if abs(rotation) < 1.0e-6: return

    axis = np.cross(a1.position - a2.position, a3.position - a2.position) # do vecs need to be normalized?
    if not adjustmol:
        rotmat_l = external.transformations.rotation_matrix(rotation / 2.0, axis, a2.position)
        rotmat_r = external.transformations.rotation_matrix(-rotation / 2.0, axis, a2.position)

        a1.position = apply_4x4_transform(rotmat_l, a1.position)
        a3.position = apply_4x4_transform(rotmat_r, a3.position)

    else:
        mol = a2.molecule
        indices, sign = _get_fragment_indices(mol, a1, a2)
        rotmat = external.transformations.rotation_matrix(rotation, axis*sign, a2.position)
        mol.positions[indices] = apply_4x4_transform(rotmat, mol.positions[indices])
def set_dihedral(a1, a2=None, a3=None, a4=None, theta=None, adjustmol=True):
    """ Set the twist angle of atoms a1 and a4 around the central bond a2-a3. The atoms will be
    adjusted along the gradient of the angle.

    Can be called as ``set_dihedral(a1, a2, a3, a4, theta, adjustmol=True)``
              OR     ``set_dihedral(a2, a2, theta, adjustmol=True)``
              OR     ``set_dihedral(bond, theta, adjustmol=True)``

    If ``adjustmol`` is True and the topology is unambiguous, then the entire molecule's positions
    will be modified as well

    Args:
        a1 (mdt.Bond): central bond in dihedral
        a1,a2 (mdt.Atom): atoms around central bond in dihedral
        a3, a4 (mdt.Atom):
        theta (u.Scalar[angle]): new angle to set
        adjustmol (bool): Adjust all atoms on either side of this bond?
    """
    # TODO: deal with co-linear a1/a4, a2, a3 - the angle is ill-defined \
    #      (should just an arbitrary axis normal to the central bond)
    if a4 is None:
        if isinstance(a1, mdt.Bond):
            if theta is None:
                theta = a2
            a1, a2 = a1.a1, a1.a2
        if a3 is not None and theta is None:
            theta, a3 = a3, theta
        elif a3 is not None or a4 is not None or theta is None:
            raise ValueError('Invalid number of arguments for set_dihedral')
        a1, a2, a3, a4 = _infer_dihedral(a1, a2)

    current = dihedral(a1, a2, a3, a4)
    rotation = sub_angles(theta, current)
    if abs(rotation) < 1.0e-6: return

    axis = a2.position - a3.position
    if not adjustmol:
        rotmat_l = external.transformations.rotation_matrix(
            -rotation / 2.0, axis, a3.position)
        rotmat_r = external.transformations.rotation_matrix(
            rotation / 2.0, axis, a3.position)

        a1.position = apply_4x4_transform(rotmat_l, a1.position)
        a4.position = apply_4x4_transform(rotmat_r, a4.position)

    else:
        mol = a2.molecule
        indices, sign = _get_fragment_indices(mol, a3, a2)
        rotmat = external.transformations.rotation_matrix(
            rotation, axis * sign, a3.position)
        mol.positions[indices] = apply_4x4_transform(rotmat,
                                                     mol.positions[indices])
Ejemplo n.º 4
0
def set_dihedral(a1, a2=None, a3=None, a4=None, theta=None, adjustmol=True):
    """ Set the twist angle of atoms a1 and a4 around the central bond a2-a3. The atoms will be
    adjusted along the gradient of the angle.

    Can be called as ``set_dihedral(a1, a2, a3, a4, theta, adjustmol=True)``
              OR     ``set_dihedral(a2, a2, theta, adjustmol=True)``
              OR     ``set_dihedral(bond, theta, adjustmol=True)``

    If ``adjustmol`` is True and the topology is unambiguous, then the entire molecule's positions
    will be modified as well

    Args:
        a1 (mdt.Bond): central bond in dihedral
        a1,a2 (mdt.Atom): atoms around central bond in dihedral
        a3, a4 (mdt.Atom):
        theta (u.Scalar[angle]): new angle to set
        adjustmol (bool): Adjust all atoms on either side of this bond?
    """
    # TODO: deal with co-linear a1/a4, a2, a3 - the angle is ill-defined \
    #      (should just an arbitrary axis normal to the central bond)
    if a4 is None:
        if isinstance(a1, mdt.Bond):
            if theta is None:
                theta = a2
            a1, a2 = a1.a1, a1.a2
        if a3 is not None and theta is None:
            theta, a3 = a3, theta
        elif a3 is not None or a4 is not None or theta is None:
            raise ValueError('Invalid number of arguments for set_dihedral')
        a1, a2, a3, a4 = _infer_dihedral(a1, a2)

    current = dihedral(a1, a2, a3, a4)
    rotation = sub_angles(theta, current)
    if abs(rotation) < 1.0e-6: return

    axis = a2.position - a3.position
    if not adjustmol:
        rotmat_l = external.transformations.rotation_matrix((-rotation / 2.0), axis, a3.position)
        rotmat_r = external.transformations.rotation_matrix((rotation / 2.0), axis, a3.position)

        a1.position = apply_4x4_transform(rotmat_l, a1.position)
        a4.position = apply_4x4_transform(rotmat_r, a4.position)

    else:
        mol = a2.molecule
        indices, sign = _get_fragment_indices(mol, a3, a2)
        rotmat = external.transformations.rotation_matrix(rotation, axis*sign, a3.position)
        mol.positions[indices] = apply_4x4_transform(rotmat, mol.positions[indices])
Ejemplo n.º 5
0
    def transform(self, matrix):
        """ Transform this object's coordinates using the provided 4x4 matrix

        Args:
            matrix (numpy.ndarray): transformation matrix, shape=(4,4)
        """
        # TODO: deal with units ... hard because the matrix has diff units for diff columns
        assert matrix.shape == (4, 4)
        self.positions = mathutils.apply_4x4_transform(matrix, self.positions)
    def transform(self, matrix):
        """ Transform this object's coordinates using the provided 4x4 matrix

        Args:
            matrix (numpy.ndarray): transformation matrix, shape=(4,4)
        """
        # TODO: deal with units ... hard because the matrix has diff units for diff columns
        assert matrix.shape == (4, 4)
        self.positions = mathutils.apply_4x4_transform(matrix, self.positions)
def set_angle(a1, a2, a3, theta, adjustmol=True):
    """ Set the angle between bonds a1-a2 and a3-a2. The atoms will be adjusted along the
    gradient of the angle.
    If ``adjustmol`` is True and the topology is unambiguous, then the entire molecule's positions
    will be modified as well

    Args:
        a1,a2,a3 (mdt.Atom): atoms to adjust
        theta (u.Scalar[angle]): new angle to set
        adjustmol (bool): Adjust all atoms on either side of this bond?
    """
    # TODO: deal with co-linear a1, a2, a3 - the rotation axis is ill-defined in this case \
    #      (require an axis to be specified)
    # TODO: weakly cache the rotation axis so that users can set angle to 0 or 180 without losing the axis
    current = angle(a1, a2, a3)
    rotation = sub_angles(current, theta)
    if abs(rotation) < 1.0e-6: return

    axis = np.cross(a1.position - a2.position, a3.position -
                    a2.position)  # do vecs need to be normalized?
    if not adjustmol:
        rotmat_l = external.transformations.rotation_matrix(
            rotation / 2.0, axis, a2.position)
        rotmat_r = external.transformations.rotation_matrix(
            -rotation / 2.0, axis, a2.position)

        a1.position = apply_4x4_transform(rotmat_l, a1.position)
        a3.position = apply_4x4_transform(rotmat_r, a3.position)

    else:
        mol = a2.molecule
        indices, sign = _get_fragment_indices(mol, a1, a2)
        rotmat = external.transformations.rotation_matrix(
            rotation, axis * sign, a2.position)
        mol.positions[indices] = apply_4x4_transform(rotmat,
                                                     mol.positions[indices])