Beispiel #1
0
def get_min_relative_distances(struct, cutoff=10.0):
    """
    This function determines the relative distance of each site to its closest
    neighbor. We use the relative distance,
    f_ij = r_ij / (r^atom_i + r^atom_j), as a measure rather than the absolute
    distances, r_ij, to account for the fact that different atoms/species
    have different sizes.  The function uses the valence-ionic radius
    estimator implemented in pymatgen.

    Args:
        struct (Structure): input structure.
        cutoff (float): (absolute) distance up to which tentative closest
                neighbors (on the basis of relative distances) are
                to be determined.

    Returns: ([float]) list of all minimum relative distances (i.e., for all
        sites).
    """
    vire = ValenceIonicRadiusEvaluator(struct)
    min_rel_dists = []
    for site in vire.structure:
        min_rel_dists.append(min([dist/(vire.radii[site.species_string]+\
            vire.radii[neigh.species_string]) for neigh, dist in \
            vire.structure.get_neighbors(site, cutoff)]))
    return min_rel_dists[:]
Beispiel #2
0
def get_site_features(s, site_idx):
    
    vire = ValenceIonicRadiusEvaluator(s)
    if np.linalg.norm(s[site_idx].coords - vire.structure[site_idx].coords) > 1e-6:
        raise RuntimeError("Mismatch between input structure and VIRE structure.")
    sa = StructuralAttribute(vire.structure)
    nn = sa.get_neighbors_of_site_with_index(site_idx)
    rn = vire.radii[vire.structure[site_idx].species_string]
    bond_lengths = [s[site_idx].distance_from_point(x.coords) * (vire.radii[x.species_string]/(rn+vire.radii[x.species_string])) for x in nn]
    #bond_lengths = [s[site_idx].distance_from_point(x.coords) for x in nn]
    # Z, valence, coordination number, weighted avg bond length
    return vire.structure[site_idx].specie.number, vire.valences[vire.structure[site_idx].species_string], len(nn),  np.mean(bond_lengths) #, np.std(bond_lengths)
Beispiel #3
0
def get_redf(struct, cutoff=None, dr=0.05):
    """
    This function permits the calculation of the crystal structure-inherent electronic radial distribution function
    (ReDF) according to Willighagen et al., Acta Cryst., 2005, B61, 29-36. The ReDF is a structure-integral RDF (i.e.,
    summed over all sites) in which the positions of neighboring sites are weighted by electrostatic interactions
    inferred from atomic partial charges. Atomic charges are obtained from the ValenceIonicRadiusEvaluator class.

    Args:
        struct (Structure): input Structure object.
        cutoff (float): distance up to which the ReDF is to be
                calculated (default: longest diagaonal in primitive cell)
        dr (float): width of bins ("x"-axis) of ReDF (default: 0.05 A).

    Returns: (dict) a copy of the electronic radial distribution functions (ReDF) as a dictionary. The distance list
        ("x"-axis values of ReDF) can be accessed via key 'distances'; the ReDF itself via key 'redf'.
    """
    if dr <= 0:
        raise ValueError("width of bins for ReDF must be >0")

    # make primitive
    struct = SpacegroupAnalyzer(struct).find_primitive() or struct

    # add oxidation states
    struct = ValenceIonicRadiusEvaluator(struct).structure

    if cutoff is None:
        # set cutoff to longest diagonal
        a = struct.lattice.matrix[0]
        b = struct.lattice.matrix[1]
        c = struct.lattice.matrix[2]
        cutoff = max([
            np.linalg.norm(a + b + c),
            np.linalg.norm(-a + b + c),
            np.linalg.norm(a - b + c),
            np.linalg.norm(a + b - c)
        ])

    nbins = int(cutoff / dr) + 1
    redf_dict = {
        "distances": np.array([(i + 0.5) * dr for i in range(nbins)]),
        "redf": np.zeros(nbins, dtype=np.float)
    }

    for site in struct.sites:
        this_charge = float(site.specie.oxi_state)
        neighs_dists = struct.get_neighbors(site, cutoff)
        for neigh, dist in neighs_dists:
            neigh_charge = float(neigh.specie.oxi_state)
            bin_index = int(dist / dr)
            redf_dict["redf"][bin_index] += (this_charge * neigh_charge) / (
                struct.num_sites * dist)

    return redf_dict
Beispiel #4
0
def get_neighbors_of_site_with_index(struct, n, p=None):
    """
    Determine the neighbors around the site that has index n in the input
    Structure object struct, given the approach defined by parameters
    p.  All supported neighbor-finding approaches and listed and
    explained in the following.  All approaches start by creating a
    tentative list of neighbors using a large cutoff radius defined in
    parameter dictionary p via key "cutoff".
    "min_dist": find nearest neighbor and its distance d_nn; consider all
            neighbors which are within a distance of d_nn * (1 + delta),
            where delta is an additional parameter provided in the
            dictionary p via key "delta".
    "scaled_VIRE": compute the radii, r_i, of all sites on the basis of
            the valence-ionic radius evaluator (VIRE); consider all
            neighbors for which the distance to the central site is less
            than the sum of the radii multiplied by an a priori chosen
            parameter, delta,
            (i.e., dist < delta * (r_central + r_neighbor)).
    "min_relative_VIRE": same approach as "min_dist", except that we
            use relative distances (i.e., distances divided by the sum of the
            atom radii from VIRE).
    "min_relative_OKeeffe": same approach as "min_relative_VIRE", except
            that we use the bond valence parameters from O'Keeffe's bond valence
            method (J. Am. Chem. Soc. 1991, 3226-3229) to calculate
            relative distances.

    Args:
        struct (Structure): input structure.
        n (int): index of site in Structure object for which
                neighbors are to be determined.
        p (dict): specification (via "approach" key; default is "min_dist")
                and parameters of neighbor-finding approach.
                Default cutoff radius is 6 Angstrom (key: "cutoff").
                Other default parameters are as follows.
                min_dist: "delta": 0.15;
                min_relative_OKeeffe: "delta": 0.05;
                min_relative_VIRE: "delta": 0.05;
                scaled_VIRE: "delta": 2.

    Returns: ([site]) list of sites that are considered to be nearest
            neighbors to site with index n in Structure object struct.
    """
    sites = []
    if p is None:
        p = {"approach": "min_dist", "delta": 0.1, "cutoff": 6}

    if p["approach"] not in [
            "min_relative_OKeeffe", "min_dist", "min_relative_VIRE", \
            "scaled_VIRE"]:
        raise RuntimeError("Unsupported neighbor-finding approach"
                           " (\"{}\")".format(p["approach"]))

    if p["approach"] == "min_relative_OKeeffe" or p["approach"] == "min_dist":
        neighs_dists = struct.get_neighbors(struct[n], p["cutoff"])
        try:
            eln = struct[n].specie.element
        except:
            eln = struct[n].species_string
    elif p["approach"] == "scaled_VIRE" or p["approach"] == "min_relative_VIRE":
        vire = ValenceIonicRadiusEvaluator(struct)
        if np.linalg.norm(struct[n].coords - vire.structure[n].coords) > 1e-6:
            raise RuntimeError(
                "Mismatch between input structure and VIRE structure.")
        neighs_dists = vire.structure.get_neighbors(vire.structure[n],
                                                    p["cutoff"])
        rn = vire.radii[vire.structure[n].species_string]

    reldists_neighs = []
    for neigh, dist in neighs_dists:
        if p["approach"] == "scaled_VIRE":
            dscale = p["delta"] * (vire.radii[neigh.species_string] + rn)
            if dist < dscale:
                sites.append(neigh)
        elif p["approach"] == "min_relative_VIRE":
            reldists_neighs.append(
                [dist / (vire.radii[neigh.species_string] + rn), neigh])
        elif p["approach"] == "min_relative_OKeeffe":
            try:
                el2 = neigh.specie.element
            except:
                el2 = neigh.species_string
            reldists_neighs.append(
                [dist / get_okeeffe_distance_prediction(eln, el2), neigh])
        elif p["approach"] == "min_dist":
            reldists_neighs.append([dist, neigh])

    if p["approach"] == "min_relative_VIRE" or \
            p["approach"] == "min_relative_OKeeffe" or \
            p["approach"] == "min_dist":
        min_reldist = min([reldist for reldist, neigh in reldists_neighs])
        for reldist, neigh in reldists_neighs:
            if reldist / min_reldist < 1.0 + p["delta"]:
                sites.append(neigh)

    return sites
def get_neighbors_of_site_with_index(struct, n, p={}):
    """
    Determine the neighbors around the site that has index n in the input
    Structure object struct, given a pre-defined approach.  So far,
    "scaled_VIRE" and "min_relative_VIRE" are implemented
    (VIRE = valence-ionic radius evaluator).

    Args:
        struct (Structure): input structure.
        n (int): index of site in Structure object for which
                neighbors are to be determined.
        p (dict): specification ("approach") and parameters of
                neighbor-finding approach.
                min_relative_VIRE (default): "delta_scale" (0.05)
                and "scale_cut" (4);
                scaled_VIRE: "scale" (2) and "scale_cut" (4).

    Returns: ([site]) list of sites that are considered to be nearest
            neighbors to site with index n in Structure object struct.
    """
    sites = []
    if p == {}:
        p = {
            "approach": "min_relative_VIRE",
            "delta_scale": 0.05,
            "scale_cut": 4
        }
    if p["approach"] == "scaled_VIRE" or p["approach"] == "min_relative_VIRE":
        vire = ValenceIonicRadiusEvaluator(struct)
        if np.linalg.norm(struct[n].coords - vire.structure[n].coords) > 1e-6:
            raise RuntimeError(
                "Mismatch between input structure and VIRE structure.")
        maxr = p["scale_cut"] * 2.0 * max(vire.radii.values())
        neighs_dists = vire.structure.get_neighbors(vire.structure[n], maxr)
        #print(len(neighs_dists))
        rn = vire.radii[vire.structure[n].species_string]
        #print(str(vire.structure[n]))
        reldists_neighs = []
        for neigh, dist in neighs_dists:
            if p["approach"] == "scaled_VIRE":
                dscale = p["scale"] * (vire.radii[neigh.species_string] + rn)
                #print("{} {}".format(dist, dscale))
                if dist < dscale:
                    sites.append(neigh)
                    #print(str(neigh))
            else:
                reldists_neighs.append(
                    [dist / (vire.radii[neigh.species_string] + rn), neigh])
        if p["approach"] == "min_relative_VIRE":
            reldists_neighs_sorted = sorted(reldists_neighs)
            max_reldist = reldists_neighs_sorted[0][0] + p["delta_scale"]
            for reldist, neigh in reldists_neighs_sorted:
                if reldist < max_reldist:
                    sites.append(neigh)
                else:
                    break
            #for reldist, neigh in reldists_neighs_sorted:
            #    print(str(reldist))
            #print(str(sites))
    else:
        raise RuntimeError("Unsupported neighbor-finding approach"
                           " (\"{}\")".format(p["approach"]))
    return sites