Beispiel #1
0
    def align_geometries_from_files(self, structure, reference_structure):
        self.structure_atoms, self.structure = kb.get_coordinates(structure)
        self.reference_structure_atoms, self.reference_structure = kb.get_coordinates(reference_structure)

        self.structure_centroid = kb.centroid(self.structure)
        self.reference_structure_centroid = kb.centroid(self.reference_structure)

        self.structure -= self.structure_centroid
        self.reference_structure -= self.reference_structure_centroid

        self.structure_aligned, self.rmsd_error = kb.kabsch(self.structure, self.reference_structure, output=True)
        self.structure_aligned += self.reference_structure_centroid
Beispiel #2
0
 def align(current: np.ndarray, reference: np.ndarray):
     """Align two geometries using Kabsch algorithm."""
     # Getting structures to be fitted
     geo = current.copy()
     ref_geo = reference.copy()
     # Computation of the centroids
     geo_centroid = kb.centroid(geo)
     ref_centroid = kb.centroid(ref_geo)
     # Translation of structures
     geo -= geo_centroid
     ref_geo -= ref_centroid
     aligned, rmsd_error = kb.kabsch(geo, ref_geo, output=True)
     return aligned, rmsd_error
Beispiel #3
0
def align_one(work_frag,
              ref_frag,
              save_matrix=False,
              mat_path=None,
              save_center=False,
              frameid=None):
    """Align only one geometry to a reference geometry.

    ref_frag : dict/Fragment
        Information of the reference fragment used for the aligning.
    save_matrices :  bool
        Weather to save the `rot_matrices` and the `centers` to files.
    mat_path : str
        Path where to save the matrices when `save_matrices` is set to True.
    """
    if isinstance(work_frag, Fragment):
        atoms = work_frag.atoms
        work_geo = work_frag.coords
    elif isinstance(work_frag, dict):
        is_ensemble = False
        atoms = work_frag['atoms']
        work_geo = work_frag['coords']
    else:
        raise TypeError(
            """Geometries to be aligned must be given either as a dict(atoms, geos)"""
            """ or as an instance of the Ensemble object.""")
    # Check ref_frag types
    if isinstance(ref_frag, Fragment):
        ref_atoms = ref_frag.atoms
        ref_geo = ref_frag.coords
    elif isinstance(ref_frag, dict):
        ref_atoms = ref_frag['atoms']
        ref_geo = ref_frag['coords']
        if isinstance(ref_geo, list):
            tmp = np.array(ref_geo)
            if tmp.shape[1] != 3:
                raise ValueError(
                    'Expecting one single geometry, with shape (natoms, 3).')
    ref_center, rot_matrix = perform_kabsch(ref_geo, work_geo, centered=False)
    work_center = centroid(work_geo)
    new_geo = _core_align(rot_matrix, ref_center, work_geo, work_center)
    # Replace values
    if not is_ensemble:
        work_frag['coords'][:] = new_geo.copy()
    else:
        work_frag.coords[:] = new_geo.copy()
    # Save matrices
    if save_matrix:
        if mat_path is None:
            mat_path = os.getcwd()
        rot_path = os.path.join(mat_path, 'rot_matrices')
        if not os.path.isdir(rot_path):
            os.mkdir(rot_path)
        if frameid is None:
            np.savetxt(os.path.join(rot_path, 'rot_matri.txt'), rot_matrix)
        else:
            np.savetxt(os.path.join(rot_path, 'rot_matrix_%d.txt' % frameid),
                       rot_matrix)
        if save_center:
            np.savetxt(os.path.join(mat_path, 'ref_center.txt'), ref_center)
def centroid_distance(ref_geo, work_geo):
    """Compute the distance between the centroids of two geometries.

    Parameters
    ----------
    ref_geo : np.ndarray
        Geometry of the reference fragment/molecule.
    work_geo : np.ndarray
        Geometry of the working fragment/molecule.

    Returns
    -------
    distance : float
        Distance between the two centroids.
    """
    ref_centroid = centroid(ref_geo)
    work_centroid = centroid(work_geo)
    return np.linalg.norm(ref_centroid - work_centroid)
Beispiel #5
0
def _align_from_matrices(geos_ensemble, mat_path=None):
    """
    Parameters
    ----------
    geos_ensemble : dict/Ensemble
        Collection of frames with atoms, coordinates (and charges) of a fragment.
    mat_path : str
        Path where to save the matrices when `save_matrices` is set to True.
    """
    # Check path
    if mat_path is None:
        mat_path = os.getcwd()
    rot_path = os.path.join(mat_path, 'rot_matrices')
    if not os.path.isdir(rot_path):
        raise ValueError('Missing `rot_matrices` folder')
    # Check geos_ensemble types
    if isinstance(geos_ensemble, Ensemble):
        is_ensemble = True
        latoms = list()
        lcoords = list()
        lframeids = list()
        for iframe in range(geos_ensemble.nframes):
            ifrag = geos_ensemble.fragments[iframe]
            latoms.append(ifrag.atoms)
            lcoords.append(ifrag.coords)
            lframeids.append(ifrag.frameid)
    elif isinstance(geos_ensemble, dict):
        is_ensemble = False
        latoms = geos_ensemble['atoms']
        lcoords = geos_ensemble['coords']
        lframeids = geos_ensemble['frameids']
    else:
        raise TypeError(
            """Geometries to be aligned must be given either as a dict(atoms, geos)"""
            """ or as an instance of the Ensemble object.""")
    # Loop over frames
    nframes = len(latoms)
    if nframes != len(lcoords):
        raise ValueError('Number of atoms and coordinates does not match.')
    ref_center = np.loadtxt(os.path.join(mat_path, 'ref_center.txt'))
    for iframe in range(nframes):
        # Read matrices
        frameid = lframeids[iframe]
        work_geo = lcoords[iframe]
        work_center = centroid(work_geo)
        rot_matrix = np.loadtxt(
            os.path.join(rot_path, 'rot_matrix_%d.txt' % frameid))
        new_geo = _core_align(rot_matrix, ref_center, work_geo, work_center)
        # Replace values
        if not is_ensemble:
            geos_ensemble['coords'][iframe][:] = new_geo.copy()
        else:
            geos_ensemble.fragments[iframe].coords[:] = new_geo.copy()
Beispiel #6
0
    def align(self, structure, reference_structure):
        """The Kabsch algorithm

        http://en.wikipedia.org/wiki/Kabsch_algorithm

        The algorithm starts with two sets of paired points of structure P and
        reference_structure Q. It returns a rotation matrix U prividing the
        best fit between the two structures,  a measure of that fit RMSD and a
        new geometry of structure P aligned to reference_structure Q.
        Each vector set P and Q is represented as an NxD matrix,  where D is the
        dimension of the space and N is the number of atoms

        The algorithm works in three steps:
        - a translation of P and Q
        - the computation of a covariance matrix C
        - computation of the optimal rotation matrix U

        The optimal rotation matrix U is then used to
        rotate P unto Q so the RMSD can be caculated
        from a straight forward fashion.

        Arguments
        ----------
        structure : ndarray
            2D ndarray [Number_of_atoms,  XYZ coordinates] contains a geometry of structure.
        reference_structure : ndarray
            2D ndarray [Number_of_atoms,  XYZ coordinates] contains a geometry of reference_structure.

        Returns
        ----------
        structure_aligned : ndarray
            2D ndarray shape(Number_of_atoms,  XYZ coordinates) contains a transformed
            coordinates of 'structure' aligned to 'reference_structure'
        U : ndarray
            3D ndarray the ebst rotation matrix.
        rmsd : float64
            RMSD between 'structure_aligned' and 'reference_structure'.
        structure_centroid : ndarray
            1D numpy array containing the coordinates of the 'structure' centroid.
        reference_structure_centroid : ndarray
            1D array containing the coordinates of the 'reference_structure' centroid.

        """

        # Getting structures to be fitted
        self.structure = structure.copy()
        self.reference_structure = reference_structure.copy()
        # Computation of the centroids
        self.structure_centroid = kb.centroid(self.structure)
        self.reference_structure_centroid = kb.centroid(self.reference_structure)
        # Translation of structures
        self.structure -= self.structure_centroid
        self.reference_structure -= self.reference_structure_centroid
        # Get initial RMSD
        # Computation of the covariance matrix
        self.covariation_matrix = np.dot(np.transpose(self.structure), self.reference_structure)

        # Computation of the optimal rotation matrix
        # This can be done using singular value decomposition (SVD)
        # Getting the sign of the det(V)*(W) to decide
        # whether we need to correct our rotation matrix to ensure a
        # right-handed coordinate system.
        # And finally calculating the optimal rotation matrix U
        # see http://en.wikipedia.org/wiki/Kabsch_algorithm
        V,  S,  W = np.linalg.svd(self.covariation_matrix)
        if (np.linalg.det(V) * np.linalg.det(W)) < 0.0:
            S[-1] = -S[-1]
            V[:, -1] = -V[:, -1]

        # Create Rotation matrix U
        U = np.dot(V,  W)

        # Rotate P
        self.structure_aligned = np.dot(self.structure,  U)
        return np.asarray([self.structure_aligned, U,
                           self.rmsd(self.structure_aligned, self.reference_structure),
                           self.structure_centroid, self.reference_structure_centroid])
Beispiel #7
0
def _align_from_scratch(geos_ensemble,
                        ref_frag,
                        save_matrices=False,
                        mat_path=None):
    """Align a set of geometries comparing to a reference geometry.

    Parameters
    ----------
    geos_ensemble : dict/Ensemble
        Collection of frames with atoms, coordinates (and charges) of a fragment.
    ref_frag : dict/Fragment
        Information of the reference fragment used for the aligning.
    save_matrices :  bool
        Weather to save the `rot_matrices` and the `centers` to files.
    mat_path : str
        Path where to save the matrices when `save_matrices` is set to True.
    """
    # Check geos_ensemble types
    if isinstance(geos_ensemble, Ensemble):
        is_ensemble = True
        latoms = list()
        lcoords = list()
        for iframe in range(geos_ensemble.nframes):
            ifrag = geos_ensemble.fragments[iframe]
            latoms.append(ifrag.atoms)
            lcoords.append(ifrag.coords)
    elif isinstance(geos_ensemble, dict):
        is_ensemble = False
        latoms = geos_ensemble['atoms']
        lcoords = geos_ensemble['coords']
    else:
        raise TypeError(
            """Geometries to be aligned must be given either as a dict(atoms, geos)"""
            """ or as an instance of the Ensemble object.""")
    # Check ref_frag types
    if isinstance(ref_frag, Fragment):
        ref_atoms = ref_frag.atoms
        ref_geo = ref_frag.coords
    elif isinstance(ref_frag, dict):
        ref_atoms = np.array(ref_frag['atoms'])
        ref_geo = ref_frag['coords']
        if isinstance(ref_geo, list):
            tmp = np.array(ref_geo)
            if tmp.shape[1] != 3:
                raise ValueError(
                    'Expecting one single geometry, with shape (natoms, 3).')
    # Loop over frames
    nframes = len(latoms)
    if nframes != len(lcoords):
        raise ValueError('Number of atoms and coordinates does not match.')
    for iframe in range(nframes):
        # Check with respect to the ref_fragment
        if not (ref_atoms == latoms[iframe]).all():
            raise ValueError(
                'Atoms of frame %d do not correspond to the reference geometry'
                % iframe)
        work_geo = lcoords[iframe]
        ref_center, rot_matrix = perform_kabsch(ref_geo,
                                                work_geo,
                                                centered=False)
        work_center = centroid(work_geo)
        new_geo = _core_align(rot_matrix, ref_center, work_geo, work_center)
        # Save matrices
        if save_matrices:
            if mat_path is None:
                mat_path = os.getcwd()
            rot_path = os.path.join(mat_path, 'rot_matrices')
            if not os.path.isdir(rot_path):
                os.mkdir(rot_path)
            if iframe == 0:
                np.savetxt(os.path.join(mat_path, 'ref_center.txt'),
                           ref_center)
            np.savetxt(os.path.join(rot_path, 'rot_matrix_%d.txt' % iframe),
                       rot_matrix)
        # Replace values
        if not is_ensemble:
            geos_ensemble['coords'][iframe][:] = new_geo.copy()
        else:
            geos_ensemble.frag[iframe].coords[:] = new_geo.copy()