Search code examples
pythongraphpymatgen

Get graph from a structure with pymatgen


Given a cif file I want to obtain the graph representation (as a data structure) of a certain material. I am trying with this cif file which represents the unit cell of CrN.

CrN

I am trying to use pymatgen's StructureGraph class but I have had some problems. In this link they suggest to use the with_local_env_strategy() method, however when I try to use it I get an error. Here my code:

from pymatgen.analysis.graphs import StructureGraph
from pymatgen.analysis.local_env import NearNeighbors
from pymatgen.core import Structure

filename = 'CrN.cif'
structure = Structure.from_file(filename)
nn = NearNeighbors()
strategy = nn.get_all_nn_info(structure)
strucGraph = StructureGraph.with_local_env_strategy(supercell, strategy, weights=False, edge_properties=False)

The error:

enter image description here


Solution

  • Since I am not an expert in the materials subject (I am only a systems engineer and a mathematician), I made these 2 possible solutions:

    Using the get_neighbors() method which, given a spherical neighborhood of a given radius, obtains the nearest neighbors:

    from pymatgen.core import Structure
    import networkx as nx
    import numpy as np
    
    filename = 'CrN.cif'
    structure = Structure.from_file(filename)
    supercell = structure.copy()
    supercell.make_supercell([2,2,2])
    G = nx.Graph()
    for i, site in enumerate(supercell):
        G.add_node(i)
        G.nodes[i]["Species"] = label_set[site.species]
        G.nodes[i]["position"] = (site.x, site.y, site.z)
    
    for i, site in enumerate(supercell):
        neighbors = [(n.index, n.nn_distance) for n in supercell.get_neighbors(site, r=3)]
        for n in neighbors:
            G.add_edge(i, n[0], weight=n[1])
    

    The second method is a little more customizable, the code I put here takes into account Euclidean distance, however, for the criterion of connection of 2 atoms can be used other criteria, such as energy.

    def space_euclidean_distance(p1, p2):
        dist = np.sqrt(np.sum((p1-p2)**2, axis=0))
        return dist
    
    lattice = supercell.lattice
    fractional_coords = supercell.frac_coords
    
    # Convert the fractional coordinates to Cartesian coordinates using the lattice vectors
    cartesian_coords = lattice.get_cartesian_coords(fractional_coords)
    distances = []
    N = len(cartesian_coords)
    for i in range(N):
        p1 = cartesian_coords[i]
        dist_i = {}
        for j in range(N):
            p2 = cartesian_coords[j]
            if j != i:
                dist_i[j] = space_euclidean_distance(p1, p2)
        distances.append(dist_i)
    
    G2 = nx.Graph()
    for i, site in enumerate(supercell):
        G2.add_node(i)
        G2.nodes[i]["Species"] = label_set[site.species]
    for i in range(N):
        for key, value in distances[i].items():
            if value <= 2.5: #metric for connection of 2 atoms
                G2.add_edge(i, key, weight=value)