Get graph from a structure with pymatgen

Question:

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

Asked By: suribe06

||

Answers:

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)
Answered By: suribe06

You must pass an instance of the strategy, not the extracted neighbors themselves. The following code should work.

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, nn, weights=False, edge_properties=False)

I assume you have created a supercell from your Structure object and then passing it in.

Answered By: Pravan Omprakash
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.