wmaee.scopes.structural_analysis

 1import numpy as np
 2import pandas as pd
 3from itertools import product
 4
 5def rdf(struct, rmin=1, rmax=10, nbins=90):
 6    """
 7    Calculate radial distribution function (RDF) for a given structure
 8    :param struct: (pymatgen.Structure) the structure
 9    :param rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
10    :param rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
11    :param nbins: (int) number of bins (points) along the radial mesh (default: 90)
12    :return: (r:numpy.array, rdf:numpy.array) radial mesh, RDF
13    """   
14
15    # define radial mesh for RDF
16    bin_edges = np.linspace(rmin, rmax, nbins+1)
17    r = [0.5*(bin_edges[i+1]+bin_edges[i]) for i in range(len(bin_edges)-1)]
18    dr = [(bin_edges[i+1]+bin_edges[i]) for i in range(len(bin_edges)-1)]
19
20    sc = [int(np.ceil(rmax/length)) for length in struct.lattice.abc]
21    struct.make_supercell(sc)
22    dists = struct.distance_matrix.reshape(-1)
23    hist, _ = np.histogram(dists, bins=bin_edges)
24    return np.array(r), np.array([hist[i]/(4*np.pi*r[i]**2*dr[i]) for i in range(len(hist))])
25
26def rdf_partial(struct, rmin=1, rmax=10, nbins=90):
27    """
28    Calculate radial distribution function (RDF) including all partial RDFs for a given structure
29    :param struct: (pymatgen.Structure) the structure
30    :param rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
31    :param rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
32    :param nbins: (int) number of bins (points) along the radial mesh (default: 90)
33    :return: (pandas.DataFrame) [R, RDF_tot, RDF_X-X, RDF_X-Y, ...]
34    """
35
36    bin_width = (rmax-rmin)/nbins
37
38    # get elements for partial RDF
39    species = sorted(list(struct.symbol_set))
40    cols = tuple(species[i]+'-'+species[j] for i in range(len(species)) for j in range(i, len(species)))
41
42    # create empty RDF
43    RDF = pd.DataFrame(columns=('r', 'tot') + cols)
44    row = {col: 0 for col in cols}
45    row['tot'] = 0
46    for i in range(nbins):
47        row['r'] = rmin+(i+0.5)*bin_width
48        RDF = RDF.append(row, ignore_index=True)
49        
50    # get SC sizes necessary for covering the desired range
51    SC = [int(np.ceil(rmax/length)) for length in struct.lattice.abc]
52    shifts = product(np.arange(-SC[0], SC[0]+1), np.arange(-SC[1], SC[1]+1), np.arange(-SC[2], SC[2]+1))
53    # list of translational vertors to be applied during RDF evaluation to go beyond
54    # period boundaries
55    shifts = [np.dot(shift, struct.lattice.matrix) for shift in shifts]
56
57    # for s in struct.sites:
58    for s in struct.sites:
59        for t in struct.sites:
60            # which bond
61            col = '-'.join(sorted([s.species_string, t.species_string]))
62            # get all SC distances
63            dist = [np.linalg.norm(s.coords-t.coords+shift) for shift in shifts]
64            iR = np.floor((np.array(dist)-rmin)/bin_width).astype(int)
65            for i in iR:
66                if i>=0 and i<nbins:
67                    RDF['tot'][i] += 1
68                    RDF[col][i] += 1
69
70    # normalize per area
71    RDF['tot'] = RDF['tot']/(4*np.pi*bin_width*RDF['r']**2)
72    for col in cols:
73        RDF[col] = RDF[col]/(4*np.pi*bin_width*RDF['r']**2)
74    
75    return RDF
def rdf(struct, rmin=1, rmax=10, nbins=90):
 6def rdf(struct, rmin=1, rmax=10, nbins=90):
 7    """
 8    Calculate radial distribution function (RDF) for a given structure
 9    :param struct: (pymatgen.Structure) the structure
10    :param rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
11    :param rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
12    :param nbins: (int) number of bins (points) along the radial mesh (default: 90)
13    :return: (r:numpy.array, rdf:numpy.array) radial mesh, RDF
14    """   
15
16    # define radial mesh for RDF
17    bin_edges = np.linspace(rmin, rmax, nbins+1)
18    r = [0.5*(bin_edges[i+1]+bin_edges[i]) for i in range(len(bin_edges)-1)]
19    dr = [(bin_edges[i+1]+bin_edges[i]) for i in range(len(bin_edges)-1)]
20
21    sc = [int(np.ceil(rmax/length)) for length in struct.lattice.abc]
22    struct.make_supercell(sc)
23    dists = struct.distance_matrix.reshape(-1)
24    hist, _ = np.histogram(dists, bins=bin_edges)
25    return np.array(r), np.array([hist[i]/(4*np.pi*r[i]**2*dr[i]) for i in range(len(hist))])

Calculate radial distribution function (RDF) for a given structure

Parameters
  • struct: (pymatgen.Structure) the structure
  • rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
  • rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
  • nbins: (int) number of bins (points) along the radial mesh (default: 90)
Returns

(r:numpy.array, rdf:numpy.array) radial mesh, RDF

def rdf_partial(struct, rmin=1, rmax=10, nbins=90):
27def rdf_partial(struct, rmin=1, rmax=10, nbins=90):
28    """
29    Calculate radial distribution function (RDF) including all partial RDFs for a given structure
30    :param struct: (pymatgen.Structure) the structure
31    :param rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
32    :param rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
33    :param nbins: (int) number of bins (points) along the radial mesh (default: 90)
34    :return: (pandas.DataFrame) [R, RDF_tot, RDF_X-X, RDF_X-Y, ...]
35    """
36
37    bin_width = (rmax-rmin)/nbins
38
39    # get elements for partial RDF
40    species = sorted(list(struct.symbol_set))
41    cols = tuple(species[i]+'-'+species[j] for i in range(len(species)) for j in range(i, len(species)))
42
43    # create empty RDF
44    RDF = pd.DataFrame(columns=('r', 'tot') + cols)
45    row = {col: 0 for col in cols}
46    row['tot'] = 0
47    for i in range(nbins):
48        row['r'] = rmin+(i+0.5)*bin_width
49        RDF = RDF.append(row, ignore_index=True)
50        
51    # get SC sizes necessary for covering the desired range
52    SC = [int(np.ceil(rmax/length)) for length in struct.lattice.abc]
53    shifts = product(np.arange(-SC[0], SC[0]+1), np.arange(-SC[1], SC[1]+1), np.arange(-SC[2], SC[2]+1))
54    # list of translational vertors to be applied during RDF evaluation to go beyond
55    # period boundaries
56    shifts = [np.dot(shift, struct.lattice.matrix) for shift in shifts]
57
58    # for s in struct.sites:
59    for s in struct.sites:
60        for t in struct.sites:
61            # which bond
62            col = '-'.join(sorted([s.species_string, t.species_string]))
63            # get all SC distances
64            dist = [np.linalg.norm(s.coords-t.coords+shift) for shift in shifts]
65            iR = np.floor((np.array(dist)-rmin)/bin_width).astype(int)
66            for i in iR:
67                if i>=0 and i<nbins:
68                    RDF['tot'][i] += 1
69                    RDF[col][i] += 1
70
71    # normalize per area
72    RDF['tot'] = RDF['tot']/(4*np.pi*bin_width*RDF['r']**2)
73    for col in cols:
74        RDF[col] = RDF[col]/(4*np.pi*bin_width*RDF['r']**2)
75    
76    return RDF

Calculate radial distribution function (RDF) including all partial RDFs for a given structure

Parameters
  • struct: (pymatgen.Structure) the structure
  • rmin: (float) Rmin of the radial mesh (default: 1 (Angstroem))
  • rmax: (float) Rmax of the radial mesh (default: 10 (Angstroem))
  • nbins: (int) number of bins (points) along the radial mesh (default: 90)
Returns

(pandas.DataFrame) [R, RDF_tot, RDF_X-X, RDF_X-Y, ...]