def Bond_angle(pmg_struct, label2site_index, atom1_label,atom2_label,atom3_label):
    '''
    input: atom1_label, atom2_label, atom3_label -- str,  Ex) Fe5, O1, etc. 
            label2site_index -- dictionary defined in script
            pmg_struct -- pymatgen structure
    output: angle -- float, Angle of (atom1-atom2-atom3) will be calculated.
        Angle is calculated by using shortest vector of (atom1-atom2) and 
        (atom3-atom2) within periodic boundary condition.
    '''
    atom1_pmg_index=convert_site_index(label2site_index, atom1_label)
    atom2_pmg_index=convert_site_index(label2site_index, atom2_label)
    atom3_pmg_index=convert_site_index(label2site_index, atom3_label)
        
    # Get fractional coordinates for each atoms
    atom1_fcoords=pmg_struct.sites[atom1_pmg_index].frac_coords
    atom2_fcoords=pmg_struct.sites[atom2_pmg_index].frac_coords
    atom3_fcoords=pmg_struct.sites[atom3_pmg_index].frac_coords
    # pbc_shortest_vector from atom2 to atom1
    vector1=pbc_shortest_vectors(pmg_struct.lattice,atom2_fcoords,atom1_fcoords)
    # pbc_shortest_vector from atom2 to atom3
    vector2=pbc_shortest_vectors(pmg_struct.lattice,atom2_fcoords,atom3_fcoords)
    
    # angle betseen two vectors
    # pbc_shortest_vector can digest set of sites,
    #but here we only use one 1 site to get angle.
    angle=get_angle(vector1[0][0],vector2[0][0])
    return angle
Пример #2
0
    def test_pbc_shortest_vectors(self):
        fcoords = np.array([
            [0.3, 0.3, 0.5],
            [0.1, 0.1, 0.3],
            [0.9, 0.9, 0.8],
            [0.1, 0.0, 0.5],
            [0.9, 0.7, 0.0],
        ])
        lattice = Lattice.from_parameters(8, 8, 4, 90, 76, 58)
        expected = np.array([
            [0.000, 3.015, 4.072, 3.519, 3.245],
            [3.015, 0.000, 3.207, 1.131, 4.453],
            [4.072, 3.207, 0.000, 2.251, 1.788],
            [3.519, 1.131, 2.251, 0.000, 3.852],
        ])

        vectors = coord.pbc_shortest_vectors(lattice, fcoords[:-1], fcoords)
        dists = np.sum(vectors**2, axis=-1)**0.5
        self.assertArrayAlmostEqual(dists, expected, 3)

        prev_threshold = coord.LOOP_THRESHOLD
        coord.LOOP_THRESHOLD = 0

        vectors = coord.pbc_shortest_vectors(lattice, fcoords[:-1], fcoords)
        dists = np.sum(vectors**2, axis=-1)**0.5
        self.assertArrayAlmostEqual(dists, expected, 3)

        coord.LOOP_THRESHOLD = prev_threshold
Пример #3
0
    def get_distance_and_image(self, frac_coords1, frac_coords2, jimage=None):
        """
        Gets distance between two frac_coords assuming periodic boundary
        conditions. If the index jimage is not specified it selects the j
        image nearest to the i atom and returns the distance and jimage
        indices in terms of lattice vector translations. If the index jimage
        is specified it returns the distance between the frac_coords1 and
        the specified jimage of frac_coords2, and the given jimage is also
        returned.

        Args:
            fcoords1 (3x1 array): Reference fcoords to get distance from.
            fcoords2 (3x1 array): fcoords to get distance from.
            jimage (3x1 array): Specific periodic image in terms of
                lattice translations, e.g., [1,0,0] implies to take periodic
                image that is one a-lattice vector away. If jimage is None,
                the image that is nearest to the site is found.

        Returns:
            (distance, jimage): distance and periodic lattice translations
            of the other site for which the distance applies. This means that
            the distance between frac_coords1 and (jimage + frac_coords2) is
            equal to distance.
        """
        if jimage is None:
            v, d2 = pbc_shortest_vectors(self, frac_coords1, frac_coords2,
                                         return_d2=True)
            fc = self.get_fractional_coords(v[0][0]) + frac_coords1 - \
                frac_coords2
            fc = np.array(np.round(fc), dtype=np.int)
            return np.sqrt(d2[0, 0]), fc

        mapped_vec = self.get_cartesian_coords(jimage + frac_coords2
                                               - frac_coords1)
        return np.linalg.norm(mapped_vec), jimage
Пример #4
0
 def minimum_image_vertex_coordinates(self):
     vertex_frac_coords = [v.frac_coords for v in self.vertices]
     pbc_vectors = pbc_shortest_vectors(self.central_atom.lattice,
                                        self.central_atom.frac_coords,
                                        vertex_frac_coords)[0]
     vertex_minimum_image_coords = [
         self.central_atom.coords + v for v in pbc_vectors
     ]
     return vertex_minimum_image_coords
Пример #5
0
    def get_dist_and_trans(lattice: Lattice, fc1, fc2):
        """
        get the shortest distance and corresponding translation vector between two frac coords

        :param lattice: pmg lattic obj
        :param fc1:
        :param fc2:
        :return:
        """
        v, d2 = pbc_shortest_vectors(lattice, fc1, fc2, return_d2=True)
        if len(np.array(fc1).shape) == 1:
            fc = lattice.get_fractional_coords(v[0][0]) + fc1 - fc2
        else:
            fc = np.zeros((len(fc1), len(fc2), 3))
            for i in range(len(fc1)):
                for j in range(len(fc2)):
                    fc_vector = np.dot(v[i][j], lattice.inv_matrix)
                    fc[i][j] = fc_vector + fc1[i] - fc2[j]
        return np.sqrt(d2), fc
Пример #6
0
    def get_all_distances(self, fcoords1, fcoords2):
        """
        Returns the distances between two lists of coordinates taking into
        account periodic boundary conditions and the lattice. Note that this
        computes an MxN array of distances (i.e. the distance between each
        point in fcoords1 and every coordinate in fcoords2). This is
        different functionality from pbc_diff.

        Args:
            fcoords1: First set of fractional coordinates. e.g., [0.5, 0.6,
                0.7] or [[1.1, 1.2, 4.3], [0.5, 0.6, 0.7]]. It can be a single
                coord or any array of coords.
            fcoords2: Second set of fractional coordinates.

        Returns:
            2d array of cartesian distances. E.g the distance between
            fcoords1[i] and fcoords2[j] is distances[i,j]
        """
        v, d2 = pbc_shortest_vectors(self, fcoords1, fcoords2, return_d2=True)
        return np.sqrt(d2)
Пример #7
0
    def get_all_distances(self, fcoords1, fcoords2):
        """
        Returns the distances between two lists of coordinates taking into
        account periodic boundary conditions and the lattice. Note that this
        computes an MxN array of distances (i.e. the distance between each
        point in fcoords1 and every coordinate in fcoords2). This is
        different functionality from pbc_diff.

        Args:
            fcoords1: First set of fractional coordinates. e.g., [0.5, 0.6,
                0.7] or [[1.1, 1.2, 4.3], [0.5, 0.6, 0.7]]. It can be a single
                coord or any array of coords.
            fcoords2: Second set of fractional coordinates.

        Returns:
            2d array of cartesian distances. E.g the distance between
            fcoords1[i] and fcoords2[j] is distances[i,j]
        """
        v, d2 = pbc_shortest_vectors(self, fcoords1, fcoords2, return_d2=True)
        return np.sqrt(d2)
Пример #8
0
def get_displacements(final_structure: Structure,
                      initial_structure: Structure,
                      defect_center: Union[list, int],
                      anchor_atom_index: int = None) -> dict:
    """ Return information related to atomic displacements.

    Args:
        final_structure (Structure):
            Relaxed final Structure
        initial_structure (Structure):
            Initial Structure
        defect_center (list / int):
            Fractional coordinates of a central position or an atom index.
        anchor_atom_index (int):
            Atom index that is assumed not to be moved during the structure
            optimization, which is usually the farthest atom from a defect.

    Variables:
        drift_frac_coords (np.array):
            A vector showing how the farthest atom drifts during the structure
            optimization.

    Return (dict):
        Keys:
        + initial_distances:
            Distances from a defect in the initial structure.
        + final_distances:
            Distances from a defect in the final structure.
        + displacement_vectors:
            Displacement vectors of atoms from initial to final structures.
        + displacement_norms:
            Norms of displacement vectors.
        + initial_vectors:
            Vectors from a defect position to atoms in the initial supercell.
        + final_vectors:
            Vectors from a defect position to atoms in the final supercell.
        + defect_migration_distance:
            Distance the defect migrates defined only for interstitials,
            antisites, and substituted defects.
    """
    if len(final_structure) != len(initial_structure):
        raise StructureError("The number of atoms are different between two "
                             "input structures.")
    elif final_structure.lattice != initial_structure.lattice:
        logger.warning("The lattice constants are different between two input "
                       "structures. Anchoring the farthest atom is switched "
                       "off as it bears erroneous result.")
        anchor_atom_index = None

    if anchor_atom_index:
        drift_frac_coords = final_structure[anchor_atom_index].frac_coords - \
                             initial_structure[anchor_atom_index].frac_coords
    else:
        drift_frac_coords = np.zeros(3)

    # Except for interstitials, it is assumed that the defect center is not
    # moved w.r.t. the anchoring atom.
    if isinstance(defect_center, int):
        initial_center = initial_structure[defect_center].frac_coords
        final_center = final_structure[defect_center].frac_coords
        if anchor_atom_index:
            final_fcoords = final_structure[defect_center].frac_coords
            initial_fcoords = (initial_structure[defect_center].frac_coords +
                               drift_frac_coords)
            # Note: Defect migration distance is estimated based on the initial
            #       lattice constants. Now, it is fine as anchor_atom_index is
            #       set only when the lattice constants are unchanged.
            _, d2 = pbc_shortest_vectors(lattice=initial_structure.lattice,
                                         fcoords1=final_fcoords,
                                         fcoords2=initial_fcoords,
                                         return_d2=True)
            defect_migration_distance = d2[0][0] ** 0.5

        else:
            defect_migration_distance = None

    else:
        initial_center = np.array(defect_center)
        final_center = np.array(defect_center) - drift_frac_coords
        defect_migration_distance = None

    displacement_vectors = []
    displacement_norms = []
    for final_site, initial_site in zip(final_structure, initial_structure):

        # displacement_vectors are cartesian coordinates.
        # Return of pbc_shortest_vectors is a tuple of these two lists
        # * Array of displacement vectors from fcoords1 to fcoords2.
        # * Squared distances
        # Fo both, First index is fcoords1 index, and second is fcoords2 index
        displacement_vector, d2 = \
            pbc_shortest_vectors(lattice=initial_structure.lattice,
                                 fcoords1=initial_site.frac_coords,
                                 fcoords2=(final_site.frac_coords
                                           - drift_frac_coords),
                                 return_d2=True)
        displacement_vectors.append(list(displacement_vector[0][0]))
        displacement_norms.append(d2[0][0] ** 0.5)

    initial_vectors, initial_distances_2 = \
        pbc_shortest_vectors(lattice=initial_structure.lattice,
                             fcoords1=initial_center,
                             fcoords2=initial_structure.frac_coords,
                             return_d2=True)

    initial_distances = [d2 ** 0.5 for d2 in initial_distances_2[0]]

    final_vectors, final_distances_2 = \
        pbc_shortest_vectors(lattice=final_structure.lattice,
                             fcoords1=final_center,
                             fcoords2=final_structure.frac_coords,
                             return_d2=True)

    final_distances = [d2 ** 0.5 for d2 in final_distances_2[0]]

    # angles are nan when the displacements are zero or diverged.
    # [0] is needed for the variables with double loops.
    return {"initial_distances":          initial_distances,
            "final_distances":            final_distances,
            "displacement_vectors":       displacement_vectors,
            "displacement_norms":         displacement_norms,
            "initial_vectors":            initial_vectors[0].tolist(),
            "final_vectors":              final_vectors[0].tolist(),
            "defect_migration_distance":  defect_migration_distance}
Пример #9
0
 def pbc_dist(fc1, fc2, lattice):
     v, d2 = pbc_shortest_vectors(lattice, fc1, fc2, return_d2=True)
     return math.sqrt(d2[0, 0])