Esempio n. 1
0
def quick_view(structure, bonds=True, conventional=False, transform=None, show_box=True, bond_tol=0.2, stick_radius=0.1):
    """
    A function to visualize pymatgen Structure objects in jupyter notebook using chemview package.

    Args:
        structure: pymatgen Structure
        bonds: (bool) visualize bonds. Bonds are found by comparing distances
                        to added covalent radii of pairs. Defaults to True.
        conventional: (bool) use conventional cell. Defaults to False.
        transform: (list) can be used to make supercells with pymatgen.Structure.make_supercell method
        show_box: (bool) unit cell is shown. Defaults to True.
        bond_tol: (float) used if bonds=True. Sets the extra distance tolerance when finding bonds.
        stick_radius: (float) radius of bonds.
    Returns:
        A chemview.MolecularViewer object
    """

    s = structure.copy()
    if conventional:
        s = SpacegroupAnalyzer(s).get_conventional_standard_structure()

    if transform:
        s.make_supercell(transform)
    atom_types = [i.symbol for i in s.species]

    if bonds:
        bonds = []
        for i in range(s.num_sites - 1):
            sym_i = s[i].specie.symbol
            for j in range(i + 1, s.num_sites):
                sym_j = s[j].specie.symbol
                max_d = CovalentRadius.radius[sym_i] + CovalentRadius.radius[sym_j] + bond_tol
                if s.get_distance(i, j, np.array([0,0,0])) < max_d:
                    bonds.append((i, j))
    bonds = bonds if bonds else None

    mv = MolecularViewer(s.cart_coords, topology={'atom_types': atom_types, 'bonds': bonds})

    if bonds:
        mv.ball_and_sticks(stick_radius=stick_radius)
    for i in s.sites:
        el = i.specie.symbol
        coord = i.coords
        r = CovalentRadius.radius[el]
        mv.add_representation('spheres', {'coordinates': coord.astype('float32'),
                                          'colors': [get_atom_color(el)],
                                          'radii': [r * 0.5],
                                          'opacity': 1.0})
    if show_box:
        o = np.array([0, 0, 0])
        a, b, c = s.lattice.matrix[0], s.lattice.matrix[1], s.lattice.matrix[2]
        starts = [o, o, o, a, a, b, b, c, c, a + b, a + c, b + c]
        ends = [a, b, c, a + b, a + c, b + a, b + c, c + a, c + b, a + b + c, a + b + c, a + b + c]
        colors = [0xffffff for i in range(12)]
        mv.add_representation('lines', {'startCoords': np.array(starts),
                                        'endCoords': np.array(ends),
                                        'startColors': colors,
                                        'endColors': colors})
    return mv
Esempio n. 2
0
 def get_supercell(self, isprint=True):
     struc = self.apply_strain()
     c_struc = SpacegroupAnalyzer(
         struc).get_conventional_standard_structure()
     c_struc.make_supercell(self.scaling_list)
     if isprint:
         print('Your supercell has {} atoms in total\n'.format(
             len(c_struc.sites)))
     return c_struc
Esempio n. 3
0
def find_dimension(structure_raw, tolerance=0.45, ldict=JmolNN().el_radius, standardize=True):
    """
    Algorithm for finding the dimensions of connected subunits in a crystal structure.
    This method finds the dimensionality of the material even when the material is not layered along low-index planes,
    or does not have flat layers/molecular wires.
    See details at : Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed, E. J. Data Mining for
    New Two- and One-Dimensional Weakly Bonded Solids and Lattice-Commensurate Heterostructures. Nano Lett. 2017.

    Args:
        structure (Structure): Input structure
        tolerance: length in angstroms used in finding bonded atoms. Two atoms are considered bonded if (radius of
            atom 1) + (radius of atom 2) + (tolerance) < (distance between atoms 1 and 2). Default value = 0.45, the
            value used by JMol and Cheon et al.
        ldict: dictionary of bond lengths used in finding bonded atoms. Values from JMol are used as default
        standardize: works with conventional standard structures if True. It is recommended to keep this as True.

    Returns:
        dim: dimension of the largest cluster as a string. If there are ions or molecules it returns 'intercalated
        ion/molecule'
    """
    if standardize:
        structure = SpacegroupAnalyzer(structure_raw).get_conventional_standard_structure()
    structure_save = copy.copy(structure_raw)
    connected_list1 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
    max1, min1, clusters1 = find_clusters(structure, connected_list1)
    structure.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
    connected_list2 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
    max2, min2, clusters2 = find_clusters(structure, connected_list2)
    if min2 == 1:
        dim = 'intercalated ion'
    elif min2 == min1:
        if max2 == max1:
            dim = '0D'
        else:
            dim = 'intercalated molecule'
    else:
        dim = np.log2(float(max2) / max1)
        if dim == int(dim):
            dim = str(int(dim)) + 'D'
        else:
            structure = copy.copy(structure_save)
            structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
            connected_list3 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
            max3, min3, clusters3 = find_clusters(structure, connected_list3)
            if min3 == min2:
                if max3 == max2:
                    dim = '0D'
                else:
                    dim = 'intercalated molecule'
            else:
                dim = np.log2(float(max3) / max1) / np.log2(3)
                if dim == int(dim):
                    dim = str(int(dim)) + 'D'
                else:
                    return
    return dim
Esempio n. 4
0
def find_dimension(structure_raw, tolerance=0.45, ldict=JmolNN().el_radius, standardize=True):
    """
    Algorithm for finding the dimensions of connected subunits in a crystal structure.
    This method finds the dimensionality of the material even when the material is not layered along low-index planes, or does not have flat layers/molecular wires.
    See details at : Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed, E. J. Data Mining for New Two- and One-Dimensional Weakly Bonded Solids and Lattice-Commensurate Heterostructures. Nano Lett. 2017.

    Args:
        structure (Structure): Input structure
        tolerance: length in angstroms used in finding bonded atoms. Two atoms are considered bonded if (radius of atom 1) + (radius of atom 2) + (tolerance) < (distance between atoms 1 and 2). Default value = 0.45, the value used by JMol and Cheon et al.
        ldict: dictionary of bond lengths used in finding bonded atoms. Values from JMol are used as default
        standardize: works with conventional standard structures if True. It is recommended to keep this as True.

    Returns:
        dim: dimension of the largest cluster as a string. If there are ions or molecules it returns 'intercalated ion/molecule'
    """
    if standardize:
        structure = SpacegroupAnalyzer(structure_raw).get_conventional_standard_structure()
    structure_save = copy.copy(structure_raw)
    connected_list1 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
    max1, min1, clusters1 = find_clusters(structure, connected_list1)
    structure.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
    connected_list2 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
    max2, min2, clusters2 = find_clusters(structure, connected_list2)
    if min2 == 1:
        dim = 'intercalated ion'
    elif min2 == min1:
        if max2 == max1:
            dim = '0D'
        else:
            dim = 'intercalated molecule'
    else:
        dim = np.log2(float(max2) / max1)
        if dim == int(dim):
            dim = str(int(dim)) + 'D'
        else:
            structure=copy.copy(structure_save)
            structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
            connected_list3 = find_connected_atoms(structure, tolerance=tolerance, ldict=ldict)
            max3, min3, clusters3 = find_clusters(structure, connected_list3)
            if min3 == min2:
                if max3 == max2:
                    dim = '0D'
                else:
                    dim = 'intercalated molecule'
            else:
                dim = np.log2(float(max3) / max1) / np.log2(3)
                if dim == int(dim):
                    dim = str(int(dim)) + 'D'
                else:
                    return
    return dim
Esempio n. 5
0
def cluster2(S, tol=1.1, seed_index=0, write_poscar_from_cluster=False):
    # S = Structure object
    # tol = tolerance bonding

    S = SpacegroupAnalyzer(S, 0.1).get_conventional_standard_structure()
    list_of_structures = []
    if len(S) < 20: S.make_supercell(2)
    Distance_matrix = S.distance_matrix
    #np.fill_diagonal(Distance_matrix,100)

    radii = [Elem_radius[site.species_string] for site in S.sites]
    radiiT = np.array(radii)[np.newaxis].T  #transpose of radii list
    radii_matrix = radii + radiiT * tol
    temp = Distance_matrix - radii_matrix
    binary_matrix = (temp < 0).astype(int)

    original = list(range(len(S)))
    final = []
    difference = []
    counter = 0
    while (len(original) != len(final)):
        seed = set((np.where(binary_matrix[seed_index] == 1))[0])
        cluster = seed
        NEW = seed
        check = True
        while check:
            Ss = set()
            for n in NEW:
                Ss.update(set(np.where(binary_matrix[n] == 1)[0]))
                #print n,set(np.where( binary_matrix[n]==1 )[0])

            if Ss.issubset(cluster):
                check = False
            else:
                NEW = Ss - cluster
                cluster.update(Ss)
        L = []
        cl = list(cluster)
        sites = [S[i] for i in cl]
        B = S.from_sites(sites)
        list_of_structures.append(B)
        counter += 1
        final = set(final)
        final.update(cluster)
        final = list(final)
        difference = list(set(original) - set(final))
        if (len(difference) > 0):
            seed_index = difference[0]
    return list_of_structures
Esempio n. 6
0
def quick_view(structure: Structure,
               conventional: bool = False,
               supercell: list = None) -> JsmolView:
    """A function to visualize pymatgen Structure objects in jupyter notebook using jupyter_jsmol package.

    Args:
        structure: pymatgen Structure object.
        conventional: use conventional cell. Defaults to False.
        transform: can be used to make supercells with pymatgen.Structure.make_supercell method.

    Returns:
        A jupyter widget object.
    """

    s = structure.copy()
    if conventional:
        s = SpacegroupAnalyzer(s).get_conventional_standard_structure()

    if supercell:
        s.make_supercell(supercell)

    return JsmolView.from_str(s.to('cif'))
Esempio n. 7
0
def get_dimensionality_cheon(
    structure_raw,
    tolerance=0.45,
    ldict=JmolNN().el_radius,
    standardize=True,
    larger_cell=False,
):
    """
    Algorithm for finding the dimensions of connected subunits in a structure.
    This method finds the dimensionality of the material even when the material
    is not layered along low-index planes, or does not have flat
    layers/molecular wires.

    Author: "Gowoon Cheon"
    Email: "*****@*****.**"

    See details at :

    Cheon, G.; Duerloo, K.-A. N.; Sendek, A. D.; Porter, C.; Chen, Y.; Reed,
    E. J. Data Mining for New Two- and One-Dimensional Weakly Bonded Solids and
    Lattice-Commensurate Heterostructures. Nano Lett. 2017.

    Args:
        structure_raw (Structure): A pymatgen Structure object.
        tolerance (float): length in angstroms used in finding bonded atoms.
            Two atoms are considered bonded if (radius of atom 1) + (radius of
            atom 2) + (tolerance) < (distance between atoms 1 and 2). Default
            value = 0.45, the value used by JMol and Cheon et al.
        ldict (dict): dictionary of bond lengths used in finding bonded atoms.
            Values from JMol are used as default
        standardize: works with conventional standard structures if True. It is
            recommended to keep this as True.
        larger_cell: tests with 3x3x3 supercell instead of 2x2x2. Testing with
            2x2x2 supercell is faster but misclssifies rare interpenetrated 3D
             structures. Testing with a larger cell circumvents this problem

    Returns:
        (str): dimension of the largest cluster as a string. If there are ions
        or molecules it returns 'intercalated ion/molecule'
    """
    if standardize:
        structure = SpacegroupAnalyzer(
            structure_raw).get_conventional_standard_structure()
    else:
        structure = structure_raw
    structure_save = copy.copy(structure_raw)
    connected_list1 = find_connected_atoms(structure,
                                           tolerance=tolerance,
                                           ldict=ldict)
    max1, min1, clusters1 = find_clusters(structure, connected_list1)
    if larger_cell:
        structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
        connected_list3 = find_connected_atoms(structure,
                                               tolerance=tolerance,
                                               ldict=ldict)
        max3, min3, clusters3 = find_clusters(structure, connected_list3)
        if min3 == min1:
            if max3 == max1:
                dim = "0D"
            else:
                dim = "intercalated molecule"
        else:
            dim = np.log2(float(max3) / max1) / np.log2(3)
            if dim == int(dim):
                dim = str(int(dim)) + "D"
            else:
                return None
    else:
        structure.make_supercell([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
        connected_list2 = find_connected_atoms(structure,
                                               tolerance=tolerance,
                                               ldict=ldict)
        max2, min2, clusters2 = find_clusters(structure, connected_list2)
        if min2 == 1:
            dim = "intercalated ion"
        elif min2 == min1:
            if max2 == max1:
                dim = "0D"
            else:
                dim = "intercalated molecule"
        else:
            dim = np.log2(float(max2) / max1)
            if dim == int(dim):
                dim = str(int(dim)) + "D"
            else:
                structure = copy.copy(structure_save)
                structure.make_supercell([[3, 0, 0], [0, 3, 0], [0, 0, 3]])
                connected_list3 = find_connected_atoms(structure,
                                                       tolerance=tolerance,
                                                       ldict=ldict)
                max3, min3, clusters3 = find_clusters(structure,
                                                      connected_list3)
                if min3 == min2:
                    if max3 == max2:
                        dim = "0D"
                    else:
                        dim = "intercalated molecule"
                else:
                    dim = np.log2(float(max3) / max1) / np.log2(3)
                    if dim == int(dim):
                        dim = str(int(dim)) + "D"
                    else:
                        return None
    return dim
Esempio n. 8
0
def get_structure_type(structure,
                       tol=0.1,
                       seed_index=0,
                       write_poscar_from_cluster=False):
    """
    This is a topology-scaling algorithm used to describe the
    periodicity of bonded clusters in a bulk structure.
    Args:
        structure (structure): Pymatgen structure object to classify.
        tol (float): Additional percent of atomic radii to allow
            for overlap, thereby defining bonds
            (0.1 = +10%, -0.1 = -10%)
        seed_index (int): Atom number to start the cluster.
        write_poscar_from_cluster (bool): Set to True to write a
            POSCAR file from the sites in the cluster.
    Returns:
        string. "molecular" (0D), "chain" (1D), "layered" (2D), or
            "conventional" (3D). Also includes " heterogeneous"
            if the cluster's composition is not equal to that
            of the overal structure.
    """

    # Get conventional structure to orthogonalize the lattice as
    # much as possible. A tolerance of 0.1 Angst. was suggested by
    # pymatgen developers.
    s = SpacegroupAnalyzer(structure,
                           0.1).get_conventional_standard_structure()
    heterogeneous = False

    noble_gases = ["He", "Ne", "Ar", "Kr", "Xe", "Rn"]
    if len([e for e in structure.composition if e.symbol in noble_gases]) != 0:
        type = "noble gas"
    else:
        # make 2x2x2 supercell to ensure sufficient number of atoms
        # for cluster building.
        s.make_supercell(2)

        # Distance matrix (rowA, columnB) shows distance between
        # atoms A and B, taking PBCs into account.
        distance_matrix = s.distance_matrix

        # Fill diagonal with a large number, so the code knows that
        # each atom is not bonded to itself.
        np.fill_diagonal(distance_matrix, 100)

        # Rows (`radii`) and columns (`radiiT`) of radii.
        radii = [ELEMENT_RADII[site.species_string] for site in s.sites]
        radiiT = np.array(radii)[np.newaxis].T
        radii_matrix = radii + radiiT * (1 + tol)

        # elements of temp that have value less than 0 are bonded.
        temp = distance_matrix - radii_matrix
        # True (1) is placed where temp < 0, and False (0) where
        # it is not.
        binary_matrix = (temp < 0).astype(int)

        # list of atoms bonded to the seed atom of a cluster
        seed = set((np.where(binary_matrix[seed_index] == 1))[0])
        cluster = seed
        NEW = seed
        while True:
            temp_set = set()
            for n in NEW:
                # temp_set will have all atoms, without duplicates,
                # that are connected to all atoms in NEW.
                temp_set.update(set(np.where(binary_matrix[n] == 1)[0]))

            if temp_set.issubset(cluster):
                # if temp_set has no new atoms, the search is done.
                break
            else:
                NEW = temp_set - cluster  # List of newly discovered atoms
                cluster.update(temp_set)  # cluster is updated with new atoms

        if len(cluster) == 0:  # i.e. the cluster is a single atom.
            cluster = [seed_index]  # Make sure it's not empty to write POSCAR.
            type = "molecular"

        elif len(cluster) == len(s.sites):  # i.e. all atoms are bonded.
            type = "conventional"

        else:
            cmp = Composition.from_dict(
                Counter([s[l].specie.name for l in list(cluster)]))
            if cmp.reduced_formula != s.composition.reduced_formula:
                # i.e. the cluster does not have the same composition
                # as the overall crystal; therefore there are other
                # clusters of varying composition.
                heterogeneous = True

            old_cluster_size = len(cluster)
            # Increase structure to determine whether it is
            # layered or molecular, then perform the same kind
            # of cluster search as before.
            s.make_supercell(2)
            distance_matrix = s.distance_matrix
            np.fill_diagonal(distance_matrix, 100)
            radii = [ELEMENT_RADII[site.species_string] for site in s.sites]
            radiiT = np.array(radii)[np.newaxis].T
            radii_matrix = radii + radiiT * (1 + tol)
            temp = distance_matrix - radii_matrix
            binary_matrix = (temp < 0).astype(int)

            seed = set((np.where(binary_matrix[seed_index] == 1))[0])
            cluster = seed
            NEW = seed
            check = True
            while check:
                temp_set = set()
                for n in NEW:
                    temp_set.update(set(np.where(binary_matrix[n] == 1)[0]))

                if temp_set.issubset(cluster):
                    check = False
                else:
                    NEW = temp_set - cluster
                    cluster.update(temp_set)

            if len(cluster) != 4 * old_cluster_size:
                type = "molecular"
            else:
                type = "layered"
    if heterogeneous:
        type += " heterogeneous"

    cluster_sites = [s.sites[n] for n in cluster]
    if write_poscar_from_cluster:
        s.from_sites(cluster_sites).get_primitive_structure().to(
            "POSCAR", "POSCAR")

    return type
Esempio n. 9
0
def get_structure_type(structure, tol=0.1, seed_index=0,
                       write_poscar_from_cluster=False):

    """
    This is a topology-scaling algorithm used to describe the
    periodicity of bonded clusters in a bulk structure.
    Args:
        structure (structure): Pymatgen structure object to classify.
        tol (float): Additional percent of atomic radii to allow
            for overlap, thereby defining bonds
            (0.1 = +10%, -0.1 = -10%)
        seed_index (int): Atom number to start the cluster.
        write_poscar_from_cluster (bool): Set to True to write a
            POSCAR file from the sites in the cluster.
    Returns:
        string. "molecular" (0D), "chain" (1D), "layered" (2D), or
            "conventional" (3D). Also includes " heterogeneous"
            if the cluster's composition is not equal to that
            of the overal structure.
    """

    # Get conventional structure to orthogonalize the lattice as
    # much as possible. A tolerance of 0.1 Angst. was suggested by
    # pymatgen developers.
    s = SpacegroupAnalyzer(structure, 0.1).get_conventional_standard_structure()
    heterogeneous = False

    noble_gases = ["He", "Ne", "Ar", "Kr", "Xe", "Rn"]
    if len([e for e in structure.composition if e.symbol in noble_gases]) != 0:
        type = "noble gas"
    else:
        # make 2x2x2 supercell to ensure sufficient number of atoms
        # for cluster building.
        s.make_supercell(2)

        # Distance matrix (rowA, columnB) shows distance between
        # atoms A and B, taking PBCs into account.
        distance_matrix = s.distance_matrix

        # Fill diagonal with a large number, so the code knows that
        # each atom is not bonded to itself.
        np.fill_diagonal(distance_matrix, 100)

        # Rows (`radii`) and columns (`radiiT`) of radii.
        radii = [ELEMENT_RADII[site.species_string] for site in s.sites]
        radiiT = np.array(radii)[np.newaxis].T
        radii_matrix = radii + radiiT*(1+tol)

        # elements of temp that have value less than 0 are bonded.
        temp = distance_matrix - radii_matrix
        # True (1) is placed where temp < 0, and False (0) where
        # it is not.
        binary_matrix = (temp < 0).astype(int)

        # list of atoms bonded to the seed atom of a cluster
        seed = set((np.where(binary_matrix[seed_index]==1))[0])
        cluster = seed
        NEW = seed
        while True:
            temp_set = set()
            for n in NEW:
                # temp_set will have all atoms, without duplicates,
                # that are connected to all atoms in NEW.
                temp_set.update(set(np.where(binary_matrix[n]==1)[0]))

            if temp_set.issubset(cluster):
                # if temp_set has no new atoms, the search is done.
                break
            else:
                NEW = temp_set - cluster # List of newly discovered atoms
                cluster.update(temp_set) # cluster is updated with new atoms

        if len(cluster) == 0:  # i.e. the cluster is a single atom.
            cluster = [seed_index]  # Make sure it's not empty to write POSCAR.
            type = "molecular"

        elif len(cluster) == len(s.sites): # i.e. all atoms are bonded.
            type = "conventional"

        else:
            cmp = Composition.from_dict(Counter([s[l].specie.name for l in
                                        list(cluster)]))
            if cmp.reduced_formula != s.composition.reduced_formula:
                # i.e. the cluster does not have the same composition
                # as the overall crystal; therefore there are other
                # clusters of varying composition.
                heterogeneous = True

            old_cluster_size = len(cluster)
            # Increase structure to determine whether it is
            # layered or molecular, then perform the same kind
            # of cluster search as before.
            s.make_supercell(2)
            distance_matrix = s.distance_matrix
            np.fill_diagonal(distance_matrix,100)
            radii = [ELEMENT_RADII[site.species_string] for site in s.sites]
            radiiT = np.array(radii)[np.newaxis].T
            radii_matrix = radii + radiiT*(1+tol)
            temp = distance_matrix-radii_matrix
            binary_matrix = (temp < 0).astype(int)

            seed = set((np.where(binary_matrix[seed_index]==1))[0])
            cluster = seed
            NEW = seed
            check = True
            while check:
                temp_set = set()
                for n in NEW:
                    temp_set.update(set(np.where(binary_matrix[n]==1)[0]))

                if temp_set.issubset(cluster):
                    check = False
                else:
                    NEW = temp_set - cluster
                    cluster.update(temp_set)

            if len(cluster) != 4 * old_cluster_size:
                type = "molecular"
            else:
                type = "layered"
    if heterogeneous:
        type += " heterogeneous"

    cluster_sites = [s.sites[n] for n in cluster]
    if write_poscar_from_cluster:
        s.from_sites(cluster_sites).get_primitive_structure().to("POSCAR",
                                                                 "POSCAR")

    return type
Esempio n. 10
0
def get_structure_type(structure, write_poscar_from_cluster=False):
    """
    This is a topology-scaling algorithm used to describe the
    periodicity of bonded clusters in a bulk structure.

    Args:
        structure (structure): Pymatgen structure object to classify.
        write_poscar_from_cluster (bool): Set to True to write a
            POSCAR from the sites in the cluster.

    Returns:
        string. 'molecular' (0D), 'chain', 'layered', 'heterogeneous'
            (intercalated 3D), or 'conventional' (3D)
    """

    # The conventional standard structure is much easier to work
    # with.

    structure = SpacegroupAnalyzer(
        structure).get_conventional_standard_structure()

    # Noble gases don't have well-defined bonding radii.
    if len([
            e for e in structure.composition
            if e.symbol in ['He', 'Ne', 'Ar', 'Kr', 'Xe']
    ]) != 0:
        type = 'noble gas'
    else:
        if len(structure.sites) < 45:
            structure.make_supercell(2)

        # Create a dict of sites as keys and lists of their
        # bonded neighbors as values.
        sites = structure.sites
        bonds = {}
        for site in sites:
            bonds[site] = []

        for i in range(len(sites)):
            site_1 = sites[i]
            for site_2 in sites[i + 1:]:
                if (site_1.distance(site_2) < float(
                        Element(site_1.specie).atomic_radius +
                        Element(site_2.specie).atomic_radius) * 1.1):
                    bonds[site_1].append(site_2)
                    bonds[site_2].append(site_1)

        # Assimilate all bonded atoms in a cluster; terminate
        # when it stops growing.
        cluster_terminated = False
        while not cluster_terminated:
            original_cluster_size = len(bonds[sites[0]])
            for site in bonds[sites[0]]:
                bonds[sites[0]] += [
                    s for s in bonds[site] if s not in bonds[sites[0]]
                ]
            if len(bonds[sites[0]]) == original_cluster_size:
                cluster_terminated = True

        original_cluster = bonds[sites[0]]

        if len(bonds[sites[0]]) == 0:  # i.e. the cluster is a single atom.
            type = 'molecular'
        elif len(bonds[sites[0]]) == len(sites):  # i.e. all atoms are bonded.
            type = 'conventional'
        else:
            # If the cluster's composition is not equal to the
            # structure's overall composition, it is a heterogeneous
            # compound.
            cluster_composition_dict = {}
            for site in bonds[sites[0]]:
                if Element(site.specie) in cluster_composition_dict:
                    cluster_composition_dict[Element(site.specie)] += 1
                else:
                    cluster_composition_dict[Element(site.specie)] = 1
            uniform = True
            if len(cluster_composition_dict):
                cmp = Composition.from_dict(cluster_composition_dict)
                if cmp.reduced_formula != structure.composition.reduced_formula:
                    uniform = False
            if not uniform:
                type = 'heterogeneous'
            else:
                # Make a 2x2x2 supercell and recalculate the
                # cluster's new size. If the new cluster size is
                # the same as the old size, it is a non-periodic
                # molecule. If it is 2x as big, it's a 1D chain.
                # If it's 4x as big, it is a layered material.
                old_cluster_size = len(bonds[sites[0]])
                structure.make_supercell(2)
                sites = structure.sites
                bonds = {}
                for site in sites:
                    bonds[site] = []

                for i in range(len(sites)):
                    site_1 = sites[i]
                    for site_2 in sites[i + 1:]:
                        if (site_1.distance(site_2) < float(
                                Element(site_1.specie).atomic_radius +
                                Element(site_2.specie).atomic_radius) * 1.1):
                            bonds[site_1].append(site_2)
                            bonds[site_2].append(site_1)

                cluster_terminated = False
                while not cluster_terminated:
                    original_cluster_size = len(bonds[sites[0]])
                    for site in bonds[sites[0]]:
                        bonds[sites[0]] += [
                            s for s in bonds[site] if s not in bonds[sites[0]]
                        ]
                    if len(bonds[sites[0]]) == original_cluster_size:
                        cluster_terminated = True

                if len(bonds[sites[0]]) != 4 * old_cluster_size:
                    type = 'molecular'
                else:
                    type = 'layered'

    if write_poscar_from_cluster:
        Structure.from_sites(original_cluster).to('POSCAR', 'POSCAR')

    return type
Esempio n. 11
0
                 sg_arr.append(sg)
                 enp_arr.append(enp)
                 fenp_arr.append(fenp)
                 pf_arr.append(pf)
                 bg_arr.append(bg)
                 tm_arr.append(tm)
                 ucf_arr.append(ucf)
                 ehull_arr.append(ehull)


                 scell_size = 1
             for s in structures:
                 svn=SpacegroupAnalyzer(s).get_conventional_standard_structure()
                 a, b, c = s.lattice.abc
                 svn.make_supercell([ceil(scell_size/a)+1,
                                   ceil(scell_size/b)+1,
                                   ceil(scell_size/c)+1])
                 structures_cvn.append(svn)
             parameters = {'atom_style': 'charge' ,'control_file':'/home/kamal/inelast.mod'}
             pair_styles = ['eam/alloy']
             pair_coeff_files = [os.path.join(os.getcwd(), ff)]
             file=str(ff)+'_data.json'
             f=open(file,'w')
             f.write(json.dumps([dict(ucf=ucf,mp_id=mp,icsd=icsd,sg=sg,enp=enp,fenp=fenp,pf=pf,bg=bg,tm=tm,ehull=ehull) for ucf,mp,icsd,sg,enp,fenp,pf,bg,tm,ehull in zip(ucf_arr,mp_arr,icsd_arr,sg_arr,enp_arr,fenp_arr,pf_arr,bg_arr,tm_arr,ehull_arr)]))
             f.close()
             turn_knobs = OrderedDict(
             [  
             ('STRUCTURES', structures_cvn),
             ('PAIR_STYLE', pair_styles),
             ('PAIR_COEFF', pair_coeff_files)
              ] )
Esempio n. 12
0
def quick_view(structure,
               bonds=True,
               conventional=False,
               transform=None,
               show_box=True,
               bond_tol=0.2,
               stick_radius=0.1):
    """
    A function to visualize pymatgen Structure objects in jupyter notebook using chemview package.

    Args:
        structure: pymatgen Structure
        bonds: (bool) visualize bonds. Bonds are found by comparing distances
                        to added covalent radii of pairs. Defaults to True.
        conventional: (bool) use conventional cell. Defaults to False.
        transform: (list) can be used to make supercells with pymatgen.Structure.make_supercell method
        show_box: (bool) unit cell is shown. Defaults to True.
        bond_tol: (float) used if bonds=True. Sets the extra distance tolerance when finding bonds.
        stick_radius: (float) radius of bonds.
    Returns:
        A chemview.MolecularViewer object
    """

    s = structure.copy()
    if conventional:
        s = SpacegroupAnalyzer(s).get_conventional_standard_structure()

    if transform:
        s.make_supercell(transform)
    atom_types = [i.symbol for i in s.species]

    if bonds:
        bonds = []
        for i in range(s.num_sites - 1):
            sym_i = s[i].specie.symbol
            for j in range(i + 1, s.num_sites):
                sym_j = s[j].specie.symbol
                max_d = CovalentRadius.radius[sym_i] + CovalentRadius.radius[
                    sym_j] + bond_tol
                if s.get_distance(i, j, np.array([0, 0, 0])) < max_d:
                    bonds.append((i, j))
    bonds = bonds if bonds else None

    mv = MolecularViewer(s.cart_coords,
                         topology={
                             'atom_types': atom_types,
                             'bonds': bonds
                         })

    if bonds:
        mv.ball_and_sticks(stick_radius=stick_radius)
    for i in s.sites:
        el = i.specie.symbol
        coord = i.coords
        r = CovalentRadius.radius[el]
        mv.add_representation(
            'spheres', {
                'coordinates': coord.astype('float32'),
                'colors': [get_atom_color(el)],
                'radii': [r * 0.5],
                'opacity': 1.0
            })
    if show_box:
        o = np.array([0, 0, 0])
        a, b, c = s.lattice.matrix[0], s.lattice.matrix[1], s.lattice.matrix[2]
        starts = [o, o, o, a, a, b, b, c, c, a + b, a + c, b + c]
        ends = [
            a, b, c, a + b, a + c, b + a, b + c, c + a, c + b, a + b + c,
            a + b + c, a + b + c
        ]
        colors = [0xffffff for i in range(12)]
        mv.add_representation(
            'lines', {
                'startCoords': np.array(starts),
                'endCoords': np.array(ends),
                'startColors': colors,
                'endColors': colors
            })
    return mv
Esempio n. 13
0
def display_structure(structure,
                      ax,
                      miller_index=None,
                      rotate=0,
                      repeat=None,
                      transform_to_conventional=False,
                      repeat_unitcell_edge_atoms=True,
                      draw_unit_cell=True,
                      draw_frame=False,
                      draw_legend=True,
                      legend_loc='best',
                      legend_fontsize=14,
                      padding=5.0,
                      scale=0.8,
                      decay=0.0):
    """
    Function that helps visualize the struct in a 2-D matplotlib plot
    Args:
        structure (struct): struct object to be visualized
        ax (axes): matplotlib axes with which to visualize
        miller_index (list): Viewing direction (normal to Miller plane)
        rotate (float): Rotate view around the viewing direction
                          (Miller index normal stays the same, just rotation within plane normal to Miller index)
        repeat (list): number of repeating unit cells in x,y,z to visualize
        transform_to_conventional (bool): Whether to transform input structure to conventional centering
        repeat_unitcell_edge_atoms (bool): Whether to repeat atoms that lie on the edges/corners of unit cell_length
                                          (makes the visualization look cut off more smoothly)
        draw_unit_cell (bool): flag indicating whether or not to draw cell boundaries
        draw_frame (bool): Whether to draw a frame around the plot (axis on/off)
        draw_legend (bool): Whether to draw a legend labeling the atom types
        legend_loc (string): Location of legend
        legend_fontsize (int): Fontsize of legend
        padding (float): Padding of the plot around the outermost atoms
        scale (float): radius scaling for sites
        decay (float): how the alpha-value decays along the z-axis
    """
    if miller_index is None:
        miller_index = [1, 0, 0]
    if repeat is None:
        repeat = [1, 1, 1]
    struct = structure.copy()
    if transform_to_conventional:
        struct = SpacegroupAnalyzer(
            struct).get_conventional_standard_structure()
    if repeat_unitcell_edge_atoms:
        struct = repeat_uc_edge_atoms(struct)
    struct = reorient(struct, miller_index, rotate=rotate)
    orig_cell = struct.lattice.matrix.copy()
    if repeat:
        struct.make_supercell(repeat)
    coords = np.array(sorted(struct.cart_coords, key=lambda x: x[2]))
    sites = sorted(struct.sites, key=lambda x: x.coords[2])
    alphas = 1 - decay * (np.max(coords[:, 2]) - coords[:, 2])
    alphas = alphas.clip(min=0)
    # Draw circles at sites and stack them accordingly
    for n, coord in enumerate(coords):
        r = sites[n].specie.atomic_radius * scale
        ax.add_patch(Circle(coord[:2], r, color='w', zorder=2 * n))
        color = color_dict[sites[n].species_string]
        ax.add_patch(
            Circle(coord[:2],
                   r,
                   facecolor=color,
                   alpha=alphas[n],
                   edgecolor='k',
                   lw=1,
                   zorder=2 * n + 1))
    # Draw unit cell
    if draw_unit_cell:
        a, b, c = orig_cell[0], orig_cell[1], orig_cell[2]
        n = np.array([0, 0, 1])
        # Draw basis vectors as arrows
        proj_a, proj_b, proj_c = a - np.dot(a, n) * n, b - np.dot(
            b, n) * n, c - np.dot(c, n) * n
        if (proj_a[0]**2 + proj_a[1]**2)**0.5 > 0.5:
            verts = [[0., 0.], proj_a[:2]]
            codes = [Path.MOVETO, Path.LINETO]
            path = Path(verts, codes)
            patch = FancyArrowPatch(
                path=path,
                arrowstyle="-|>,head_length=7,head_width=4",
                facecolor='black',
                lw=2,
                alpha=1,
                zorder=500)
            ax.add_patch(patch)
        if (proj_b[0]**2 + proj_b[1]**2)**0.5 > 0.5:
            verts = [[0., 0.], proj_b[:2]]
            codes = [Path.MOVETO, Path.LINETO]
            path = Path(verts, codes)
            patch = FancyArrowPatch(
                path=path,
                arrowstyle="-|>,head_length=7,head_width=4",
                facecolor='black',
                lw=2,
                alpha=1,
                zorder=500)
            ax.add_patch(patch)
        if (proj_c[0]**2 + proj_c[1]**2)**0.5 > 0.5:
            verts = [[0., 0.], proj_c[:2]]
            codes = [Path.MOVETO, Path.LINETO]
            path = Path(verts, codes)
            patch = FancyArrowPatch(
                path=path,
                arrowstyle="-|>,head_length=7,head_width=4",
                facecolor='black',
                lw=2,
                alpha=1,
                zorder=500)
            ax.add_patch(patch)

        # Draw opposing three unit cell boundaries
        abc = a + b + c - np.dot(a + b + c, n) * n
        ab = a + b - np.dot(a + b, n) * n
        ac = a + c - np.dot(a + c, n) * n
        bc = b + c - np.dot(b + c, n) * n
        verts_top = [abc[:2], ab[:2], abc[:2], ac[:2], abc[:2], bc[:2]]
        codes_top = [
            Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO,
            Path.LINETO
        ]
        path_top = Path(verts_top, codes_top)
        patch_top = patches.PathPatch(path_top,
                                      facecolor='none',
                                      lw=2,
                                      alpha=0.5,
                                      zorder=500)
        ax.add_patch(patch_top)

        # Draw remaining surrounding unit cell boundaries
        verts_surround = [
            proj_a[:2], ac[:2], proj_c[:2], bc[:2], proj_b[:2], ab[:2],
            proj_a[:2]
        ]
        codes_surround = [
            Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO,
            Path.LINETO, Path.LINETO
        ]
        path_surround = Path(verts_surround, codes_surround)
        patch_surround = patches.PathPatch(path_surround,
                                           facecolor='none',
                                           lw=2,
                                           alpha=0.5,
                                           zorder=500)
        ax.add_patch(patch_surround)

    # Legend
    if draw_legend:
        unique_sites = list({s.species_string for s in sites})
        unique_colors = [color_dict[site] for site in unique_sites]
        handles = [
            Patch(facecolor=unique_colors[i],
                  label=str(unique_sites[i]),
                  linewidth=1,
                  edgecolor='black') for i in range(len(unique_sites))
        ]
        ax.legend(handles=handles,
                  frameon=False,
                  loc=legend_loc,
                  fontsize=legend_fontsize)

    ax.set_aspect("equal")
    x_lim = [min(coords[:, 0]) - padding, max(coords[:, 0]) + padding]
    y_lim = [min(coords[:, 1]) - padding, max(coords[:, 1]) + padding]
    ax.set_xlim(x_lim)
    ax.set_ylim(y_lim)
    if not draw_frame:
        ax.axis('off')
    ax.set_xticks([])
    ax.set_yticks([])
    return ax
Esempio n. 14
0
                enp_arr.append(enp)
                fenp_arr.append(fenp)
                pf_arr.append(pf)
                bg_arr.append(bg)
                tm_arr.append(tm)
                ucf_arr.append(ucf)
                ehull_arr.append(ehull)

                scell_size = 1
            for s in structures:
                svn = SpacegroupAnalyzer(
                    s).get_conventional_standard_structure()
                a, b, c = s.lattice.abc
                svn.make_supercell([
                    ceil(scell_size / a) + 1,
                    ceil(scell_size / b) + 1,
                    ceil(scell_size / c) + 1
                ])
                structures_cvn.append(svn)
            parameters = {
                'atom_style': 'charge',
                'control_file': '/home/kamal/inelast.mod'
            }
            pair_styles = ['eam/alloy']
            pair_coeff_files = [os.path.join(os.getcwd(), ff)]
            file = str(ff) + '_data.json'
            f = open(file, 'w')
            f.write(
                json.dumps([
                    dict(ucf=ucf,
                         mp_id=mp,
Esempio n. 15
0
def get_structure_type(structure, write_poscar_from_cluster=False):
    """
    This is a topology-scaling algorithm used to describe the
    periodicity of bonded clusters in a bulk structure.

    Args:
        structure (structure): Pymatgen structure object to classify.
        write_poscar_from_cluster (bool): Set to True to write a
            POSCAR from the sites in the cluster.

    Returns:
        string. 'molecular' (0D), 'chain', 'layered', 'heterogeneous'
            (intercalated 3D), or 'conventional' (3D)
    """

    # The conventional standard structure is much easier to work
    # with.

    structure = SpacegroupAnalyzer(
        structure).get_conventional_standard_structure()

    # Noble gases don't have well-defined bonding radii.
    if not len([e for e in structure.composition
            if e.symbol in ['He', 'Ne', 'Ar', 'Kr', 'Xe']]) == 0:
        type = 'noble gas'
    else:
        if len(structure.sites) < 45:
            structure.make_supercell(2)

        # Create a dict of sites as keys and lists of their
        # bonded neighbors as values.
        sites = structure.sites
        bonds = {}
        for site in sites:
            bonds[site] = []

        for i in range(len(sites)):
            site_1 = sites[i]
            for site_2 in sites[i+1:]:
                if (site_1.distance(site_2) <
                        float(Element(site_1.specie).atomic_radius
                        + Element(site_2.specie).atomic_radius) * 1.1):
                    bonds[site_1].append(site_2)
                    bonds[site_2].append(site_1)

        # Assimilate all bonded atoms in a cluster; terminate
        # when it stops growing.
        cluster_terminated = False
        while not cluster_terminated:
            original_cluster_size = len(bonds[sites[0]])
            for site in bonds[sites[0]]:
                bonds[sites[0]] += [
                    s for s in bonds[site] if s not in bonds[sites[0]]]
            if len(bonds[sites[0]]) == original_cluster_size:
                cluster_terminated = True

        original_cluster = bonds[sites[0]]

        if len(bonds[sites[0]]) == 0:  # i.e. the cluster is a single atom.
            type = 'molecular'
        elif len(bonds[sites[0]]) == len(sites): # i.e. all atoms are bonded.
            type = 'conventional'
        else:
            # If the cluster's composition is not equal to the
            # structure's overall composition, it is a heterogeneous
            # compound.
            cluster_composition_dict = {}
            for site in bonds[sites[0]]:
                if Element(site.specie) in cluster_composition_dict:
                    cluster_composition_dict[Element(site.specie)] += 1
                else:
                    cluster_composition_dict[Element(site.specie)] = 1
            uniform = True
            if len(cluster_composition_dict):
                cmp = Composition.from_dict(cluster_composition_dict)
                if cmp.reduced_formula != structure.composition.reduced_formula:
                    uniform = False
            if not uniform:
                type = 'heterogeneous'
            else:
                # Make a 2x2x2 supercell and recalculate the
                # cluster's new size. If the new cluster size is
                # the same as the old size, it is a non-periodic
                # molecule. If it is 2x as big, it's a 1D chain.
                # If it's 4x as big, it is a layered material.
                old_cluster_size = len(bonds[sites[0]])
                structure.make_supercell(2)
                sites = structure.sites
                bonds = {}
                for site in sites:
                    bonds[site] = []

                for i in range(len(sites)):
                    site_1 = sites[i]
                    for site_2 in sites[i+1:]:
                        if (site_1.distance(site_2) <
                                float(Element(site_1.specie).atomic_radius
                                + Element(site_2.specie).atomic_radius) * 1.1):
                            bonds[site_1].append(site_2)
                            bonds[site_2].append(site_1)

                cluster_terminated = False
                while not cluster_terminated:
                    original_cluster_size = len(bonds[sites[0]])
                    for site in bonds[sites[0]]:
                        bonds[sites[0]] += [
                            s for s in bonds[site] if s not in bonds[sites[0]]]
                    if len(bonds[sites[0]]) == original_cluster_size:
                        cluster_terminated = True

                if len(bonds[sites[0]]) != 4 * old_cluster_size:
                    type = 'molecular'
                else:
                    type = 'layered'

    if write_poscar_from_cluster:
        Structure.from_sites(original_cluster).to('POSCAR', 'POSCAR')

    return type