Instruction:
How would you explain what the following Python 3 function does
def plot_zt_mu(self, temp=600, output='eig', relaxation_time=1e-14,
                   xlim=None):
        """
        Plot the ZT in function of Fermi level.

        Args:
            temp: the temperature
            xlim: a list of min and max fermi energy by default (0, and band
                gap)
            tau: A relaxation time in s. By default none and the plot is by
               units of relaxation time

        Returns:
            a matplotlib object
        """
        import matplotlib.pyplot as plt
        plt.figure(figsize=(9, 7))
        zt = self._bz.get_zt(relaxation_time=relaxation_time, output=output,
                             doping_levels=False)[temp]
        plt.plot(self._bz.mu_steps, zt, linewidth=3.0)
        self._plot_bg_limits()
        self._plot_doping(temp)
        if output == 'eig':
            plt.legend(['ZT$_1$', 'ZT$_2$', 'ZT$_3$'])
        if xlim is None:
            plt.xlim(-0.5, self._bz.gap + 0.5)
        else:
            plt.xlim(xlim)
        plt.ylabel("ZT", fontsize=30.0)
        plt.xlabel("E-E$_f$ (eV)", fontsize=30.0)
        plt.xticks(fontsize=25)
        plt.yticks(fontsize=25)
        plt.tight_layout()
        return plt

Response: Plot the ZT in function of Fermi level.


Instruction:
How would you explain what the following Python 3 function does
def plot_seebeck_temp(self, doping='all', output='average'):

        import matplotlib.pyplot as plt
        if output == 'average':
            sbk = self._bz.get_seebeck(output='average')
        elif output == 'eigs':
            sbk = self._bz.get_seebeck(output='eigs')

        plt.figure(figsize=(22, 14))
        tlist = sorted(sbk['n'].keys())
        doping = self._bz.doping['n'] if doping == 'all' else doping
        for i, dt in enumerate(['n', 'p']):
            plt.subplot(121 + i)
            for dop in doping:
                d = self._bz.doping[dt].index(dop)
                sbk_temp = []
                for temp in tlist:
                    sbk_temp.append(sbk[dt][temp][d])
                if output == 'average':
                    plt.plot(tlist, sbk_temp, marker='s',
                             label=str(dop) + ' $cm^{-3}$')
                elif output == 'eigs':
                    for xyz in range(3):
                        plt.plot(tlist, zip(*sbk_temp)[xyz], marker='s',
                                 label=str(xyz) + ' ' + str(dop) + ' $cm^{-3}$')
            plt.title(dt + '-type', fontsize=20)
            if i == 0:
                plt.ylabel("Seebeck \n coefficient  ($\\mu$V/K)", fontsize=30.0)
            plt.xlabel('Temperature (K)', fontsize=30.0)

            p = 'lower right' if i == 0 else ''
            plt.legend(loc=p, fontsize=15)
            plt.grid()
            plt.xticks(fontsize=25)
            plt.yticks(fontsize=25)

        plt.tight_layout()

        return plt

Response:
Plots the Seebeck coefficient in function of temperature for different
        doping levels.


Instruction:
Can you write a function in Python 3 where it
plots the Power Factor in function of doping levels for different temperatures.

Response:
def plot_power_factor_dop(self, temps='all', output='average',
                              relaxation_time=1e-14):
        """
        Plot the Power Factor in function of doping levels for different temperatures.

        Args:
            temps: the default 'all' plots all the temperatures in the analyzer.
                   Specify a list of temperatures if you want to plot only some.
            output: with 'average' you get an average of the three directions
                    with 'eigs' you get all the three directions.
            relaxation_time: specify a constant relaxation time value

        Returns:
            a matplotlib object
        """
        import matplotlib.pyplot as plt
        if output == 'average':
            pf = self._bz.get_power_factor(relaxation_time=relaxation_time,
                                           output='average')
        elif output == 'eigs':
            pf = self._bz.get_power_factor(relaxation_time=relaxation_time,
                                           output='eigs')

        tlist = sorted(pf['n'].keys()) if temps == 'all' else temps
        plt.figure(figsize=(22, 14))
        for i, dt in enumerate(['n', 'p']):
            plt.subplot(121 + i)
            for temp in tlist:
                if output == 'eigs':
                    for xyz in range(3):
                        plt.semilogx(self._bz.doping[dt],
                                     zip(*pf[dt][temp])[xyz],
                                     marker='s',
                                     label=str(xyz) + ' ' + str(temp) + ' K')
                elif output == 'average':
                    plt.semilogx(self._bz.doping[dt], pf[dt][temp],
                                 marker='s', label=str(temp) + ' K')
            plt.title(dt + '-type', fontsize=20)
            if i == 0:
                plt.ylabel("Power Factor  ($\\mu$W/(mK$^2$))", fontsize=30.0)
            plt.xlabel('Doping concentration ($cm^{-3}$)', fontsize=30.0)
            plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
            p = ''  # 'lower right' if i == 0 else ''
            plt.legend(loc=p, fontsize=15)
            plt.grid()
            plt.xticks(fontsize=25)
            plt.yticks(fontsize=25)

        plt.tight_layout()

        return plt


Instruction:
Create a Python 3 function for
plotting the figure of merit zT in function of doping levels for different temperatures.

Response:
def plot_zt_dop(self, temps='all', output='average', relaxation_time=1e-14):
        """
        Plot the figure of merit zT in function of doping levels for different
        temperatures.

        Args:
            temps: the default 'all' plots all the temperatures in the analyzer.
                   Specify a list of temperatures if you want to plot only some.
            output: with 'average' you get an average of the three directions
                    with 'eigs' you get all the three directions.
            relaxation_time: specify a constant relaxation time value

        Returns:
            a matplotlib object
        """
        import matplotlib.pyplot as plt
        if output == 'average':
            zt = self._bz.get_zt(relaxation_time=relaxation_time,
                                 output='average')
        elif output == 'eigs':
            zt = self._bz.get_zt(relaxation_time=relaxation_time, output='eigs')

        tlist = sorted(zt['n'].keys()) if temps == 'all' else temps
        plt.figure(figsize=(22, 14))
        for i, dt in enumerate(['n', 'p']):
            plt.subplot(121 + i)
            for temp in tlist:
                if output == 'eigs':
                    for xyz in range(3):
                        plt.semilogx(self._bz.doping[dt],
                                     zip(*zt[dt][temp])[xyz],
                                     marker='s',
                                     label=str(xyz) + ' ' + str(temp) + ' K')
                elif output == 'average':
                    plt.semilogx(self._bz.doping[dt], zt[dt][temp],
                                 marker='s', label=str(temp) + ' K')
            plt.title(dt + '-type', fontsize=20)
            if i == 0:
                plt.ylabel("zT", fontsize=30.0)
            plt.xlabel('Doping concentration ($cm^{-3}$)', fontsize=30.0)

            p = 'lower right' if i == 0 else ''
            plt.legend(loc=p, fontsize=15)
            plt.grid()
            plt.xticks(fontsize=25)
            plt.yticks(fontsize=25)

        plt.tight_layout()

        return plt


Instruction:
Write a Python 3 script to
return a matplotlib object containing the dos of the current object.

Response:
def plot_dos(self, sigma=0.05):
        """
        plot dos

        Args:
            sigma: a smearing

        Returns:
            a matplotlib object
        """
        plotter = DosPlotter(sigma=sigma)
        plotter.add_dos("t", self._bz.dos)
        return plotter.get_plot()


Instruction:
Given the following Python 3 function, write the documentation
def plot_carriers(self, temp=300):
        import matplotlib.pyplot as plt
        plt.semilogy(self._bz.mu_steps,
                     abs(self._bz._carrier_conc[temp] / (self._bz.vol * 1e-24)),
                     linewidth=3.0, color='r')
        self._plot_bg_limits()
        self._plot_doping(temp)
        plt.xlim(-0.5, self._bz.gap + 0.5)
        plt.ylim(1e14, 1e22)
        plt.ylabel("carrier concentration (cm-3)", fontsize=30.0)
        plt.xlabel("E-E$_f$ (eV)", fontsize=30)
        plt.xticks(fontsize=25)
        plt.yticks(fontsize=25)
        return plt

Response: Plot the carrier concentration in function of Fermi level


Instruction:
Write a Python 3 function that can
plot the Hall carrier concentration in function of Fermi level

Response:
def plot_hall_carriers(self, temp=300):
        """
        Plot the Hall carrier concentration in function of Fermi level

        Args:
            temp: the temperature

        Returns:
            a matplotlib object
        """
        import matplotlib.pyplot as plt
        hall_carriers = [abs(i) for i in
                         self._bz.get_hall_carrier_concentration()[temp]]
        plt.semilogy(self._bz.mu_steps,
                     hall_carriers,
                     linewidth=3.0, color='r')
        self._plot_bg_limits()
        self._plot_doping(temp)
        plt.xlim(-0.5, self._bz.gap + 0.5)
        plt.ylim(1e14, 1e22)
        plt.ylabel("Hall carrier concentration (cm-3)", fontsize=30.0)
        plt.xlabel("E-E$_f$ (eV)", fontsize=30)
        plt.xticks(fontsize=25)
        plt.yticks(fontsize=25)
        return plt


Instruction:
Can you implement a function in Python 3 that
adds a COHP object to the dictionary.

Response:
def add_cohp(self, label, cohp):
        """
        Adds a COHP for plotting.

        Args:
            label: Label for the COHP. Must be unique.

            cohp: COHP object.
        """
        energies = cohp.energies - cohp.efermi if self.zero_at_efermi \
            else cohp.energies
        populations = cohp.get_cohp()
        int_populations = cohp.get_icohp()
        self._cohps[label] = {"energies": energies, "COHP": populations,
                              "ICOHP": int_populations, "efermi": cohp.efermi}


Instruction:
How would you implement a function in Python 3 that
adds a dictionary of COHPs with an optional sorting function for the keys.

Response:
def add_cohp_dict(self, cohp_dict, key_sort_func=None):
        """
        Adds a dictionary of COHPs with an optional sorting function
        for the keys.

        Args:
            cohp_dict: dict of the form {label: Cohp}

            key_sort_func: function used to sort the cohp_dict keys.
        """
        if key_sort_func:
            keys = sorted(cohp_dict.keys(), key=key_sort_func)
        else:
            keys = cohp_dict.keys()
        for label in keys:
            self.add_cohp(label, cohp_dict[label])


Instruction:
Create a Python 3 function for
returning a matplotlib plot showing the COHPs and ICOHPs.

Response:
def get_plot(self, xlim=None, ylim=None, plot_negative=None,
                 integrated=False, invert_axes=True):
        """
        Get a matplotlib plot showing the COHP.

        Args:
            xlim: Specifies the x-axis limits. Defaults to None for
                automatic determination.

            ylim: Specifies the y-axis limits. Defaults to None for
                automatic determination.

            plot_negative: It is common to plot -COHP(E) so that the
                sign means the same for COOPs and COHPs. Defaults to None
                for automatic determination: If are_coops is True, this
                will be set to False, else it will be set to True.

            integrated: Switch to plot ICOHPs. Defaults to False.

            invert_axes: Put the energies onto the y-axis, which is
                common in chemistry.

        Returns:
            A matplotlib object.
        """
        if self.are_coops:
            cohp_label = "COOP"
        else:
            cohp_label = "COHP"

        if plot_negative is None:
            plot_negative = True if not self.are_coops else False

        if integrated:
            cohp_label = "I" + cohp_label + " (eV)"

        if plot_negative:
            cohp_label = "-" + cohp_label

        if self.zero_at_efermi:
            energy_label = "$E - E_f$ (eV)"
        else:
            energy_label = "$E$ (eV)"

        ncolors = max(3, len(self._cohps))
        ncolors = min(9, ncolors)

        import palettable

        colors = palettable.colorbrewer.qualitative.Set1_9.mpl_colors

        plt = pretty_plot(12, 8)

        allpts = []
        keys = self._cohps.keys()
        for i, key in enumerate(keys):
            energies = self._cohps[key]["energies"]
            if not integrated:
                populations = self._cohps[key]["COHP"]
            else:
                populations = self._cohps[key]["ICOHP"]
            for spin in [Spin.up, Spin.down]:
                if spin in populations:
                    if invert_axes:
                        x = -populations[spin] if plot_negative \
                            else populations[spin]
                        y = energies
                    else:
                        x = energies
                        y = -populations[spin] if plot_negative \
                            else populations[spin]
                    allpts.extend(list(zip(x, y)))
                    if spin == Spin.up:
                        plt.plot(x, y, color=colors[i % ncolors],
                                 linestyle='-', label=str(key), linewidth=3)
                    else:
                        plt.plot(x, y, color=colors[i % ncolors],
                                 linestyle='--', linewidth=3)

        if xlim:
            plt.xlim(xlim)
        if ylim:
            plt.ylim(ylim)
        else:
            xlim = plt.xlim()
            relevanty = [p[1] for p in allpts if xlim[0] < p[0] < xlim[1]]
            plt.ylim((min(relevanty), max(relevanty)))

        xlim = plt.xlim()
        ylim = plt.ylim()
        if not invert_axes:
            plt.plot(xlim, [0, 0], "k-", linewidth=2)
            if self.zero_at_efermi:
                plt.plot([0, 0], ylim, "k--", linewidth=2)
            else:
                plt.plot([self._cohps[key]['efermi'],
                         self._cohps[key]['efermi']], ylim,
                         color=colors[i % ncolors],
                         linestyle='--', linewidth=2)
        else:
            plt.plot([0, 0], ylim, "k-", linewidth=2)
            if self.zero_at_efermi:
                plt.plot(xlim, [0, 0], "k--", linewidth=2)
            else:
                plt.plot(xlim, [self._cohps[key]['efermi'],
                         self._cohps[key]['efermi']],
                         color=colors[i % ncolors],
                         linestyle='--', linewidth=2)

        if invert_axes:
            plt.xlabel(cohp_label)
            plt.ylabel(energy_label)
        else:
            plt.xlabel(energy_label)
            plt.ylabel(cohp_label)

        plt.legend()
        leg = plt.gca().get_legend()
        ltext = leg.get_texts()
        plt.setp(ltext, fontsize=30)
        plt.tight_layout()
        return plt


Instruction:
How would you implement a function in Python 3 that
returns a list of dopant suggestions for each doping type in the given structure.

Response:
def get_dopants_from_substitution_probabilities(structure, num_dopants=5,
                                                threshold=0.001,
                                                match_oxi_sign=False):
    """
    Get dopant suggestions based on substitution probabilities.

    Args:
        structure (Structure): A pymatgen structure decorated with
            oxidation states.
        num_dopants (int): The number of suggestions to return for
            n- and p-type dopants.
        threshold (float): Probability threshold for substitutions.
        match_oxi_sign (bool): Whether to force the dopant and original species
            to have the same sign of oxidation state. E.g. If the original site
            is in a negative charge state, then only negative dopants will be
            returned.

    Returns:
        (dict): Dopant suggestions, given as a dictionary with keys "n_type" and
        "p_type". The suggestions for each doping type are given as a list of
        dictionaries, each with they keys:

        - "probability": The probability of substitution.
        - "dopant_species": The dopant species.
        - "original_species": The substituted species.
    """
    els_have_oxi_states = [hasattr(s, "oxi_state") for s in structure.species]

    if not all(els_have_oxi_states):
        raise ValueError("All sites in structure must have oxidation states to "
                         "predict dopants.")

    sp = SubstitutionPredictor(threshold=threshold)

    subs = [sp.list_prediction([s]) for s in set(structure.species)]
    subs = [{'probability': pred['probability'],
             'dopant_species': list(pred['substitutions'].keys())[0],
             'original_species': list(pred['substitutions'].values())[0]}
            for species_preds in subs for pred in species_preds]
    subs.sort(key=lambda x: x['probability'], reverse=True)

    return _get_dopants(subs, num_dopants, match_oxi_sign)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_dopants_from_shannon_radii(bonded_structure, num_dopants=5,
                                   match_oxi_sign=False):
    """
    Get dopant suggestions based on Shannon radii differences.

    Args:
        bonded_structure (StructureGraph): A pymatgen structure graph
            decorated with oxidation states. For example, generated using the
            CrystalNN.get_bonded_structure() method.
        num_dopants (int): The nummber of suggestions to return for
            n- and p-type dopants.
        match_oxi_sign (bool): Whether to force the dopant and original species
            to have the same sign of oxidation state. E.g. If the original site
            is in a negative charge state, then only negative dopants will be
            returned.

    Returns:
        (dict): Dopant suggestions, given as a dictionary with keys "n_type" and
        "p_type". The suggestions for each doping type are given as a list of
        dictionaries, each with they keys:

        - "radii_diff": The difference between the Shannon radii of the species.
        - "dopant_spcies": The dopant species.
        - "original_species": The substituted species.
    """
    # get a list of all Specie for all elements in all their common oxid states
    all_species = [Specie(el, oxi) for el in Element
                   for oxi in el.common_oxidation_states]

    # get a series of tuples with (coordination number, specie)
    cn_and_species = set((bonded_structure.get_coordination_of_site(i),
                          bonded_structure.structure[i].specie)
                         for i in range(bonded_structure.structure.num_sites))

    cn_to_radii_map = {}
    possible_dopants = []

    for cn, species in cn_and_species:
        cn_roman = _int_to_roman(cn)

        try:
            species_radius = species.get_shannon_radius(cn_roman)
        except KeyError:
            warnings.warn("Shannon radius not found for {} with coordination "
                          "number {}.\nSkipping...".format(species, cn))
            continue

        if cn not in cn_to_radii_map:
            cn_to_radii_map[cn] = _shannon_radii_from_cn(
                all_species, cn_roman, radius_to_compare=species_radius)

        shannon_radii = cn_to_radii_map[cn]

        possible_dopants += [{'radii_diff': p['radii_diff'],
                              'dopant_species': p['species'],
                              'original_species': species}
                             for p in shannon_radii]

    possible_dopants.sort(key=lambda x: abs(x['radii_diff']))

    return _get_dopants(possible_dopants, num_dopants, match_oxi_sign)

Response: Returns a list of dopant suggestions for each element in the structure that are in the Shannon radii of the species.


Instruction:
Create a Python 3 function for
calculating the solid angle of a set of coords from the center.

Response:
def solid_angle(center, coords):
    """
    Helper method to calculate the solid angle of a set of coords from the
    center.

    Args:
        center (3x1 array): Center to measure solid angle from.
        coords (Nx3 array): List of coords to determine solid angle.

    Returns:
        The solid angle.
    """

    # Compute the displacement from the center
    r = [np.subtract(c, center) for c in coords]

    # Compute the magnitude of each vector
    r_norm = [np.linalg.norm(i) for i in r]

    # Compute the solid angle for each tetrahedron that makes up the facet
    #  Following: https://en.wikipedia.org/wiki/Solid_angle#Tetrahedron
    angle = 0
    for i in range(1, len(r) - 1):
        j = i + 1
        tp = np.abs(np.dot(r[0], np.cross(r[i], r[j])))
        de = r_norm[0] * r_norm[i] * r_norm[j] + \
             r_norm[j] * np.dot(r[0], r[i]) + \
             r_norm[i] * np.dot(r[0], r[j]) + \
             r_norm[0] * np.dot(r[i], r[j])
        if de == 0:
            my_angle = 0.5 * pi if tp > 0 else -0.5 * pi
        else:
            my_angle = np.arctan(tp / de)
        angle += (my_angle if my_angle > 0 else my_angle + np.pi) * 2

    return angle


Instruction:
How would you implement a function in Python 3 that
calculates the volume of a tetrahedron given the four vertices of vt1 vt2 vt3 and vt4.

Response:
def vol_tetra(vt1, vt2, vt3, vt4):
    """
    Calculate the volume of a tetrahedron, given the four vertices of vt1,
    vt2, vt3 and vt4.
    Args:
        vt1 (array-like): coordinates of vertex 1.
        vt2 (array-like): coordinates of vertex 2.
        vt3 (array-like): coordinates of vertex 3.
        vt4 (array-like): coordinates of vertex 4.
    Returns:
        (float): volume of the tetrahedron.
    """
    vol_tetra = np.abs(np.dot((vt1 - vt4),
                              np.cross((vt2 - vt4), (vt3 - vt4)))) / 6
    return vol_tetra


Instruction:
Write a Python 3 script for
returning the elemental parameters related to the element and bond length of the specified element.

Response:
def get_okeeffe_params(el_symbol):
    """
    Returns the elemental parameters related to atom size and
    electronegativity which are used for estimating bond-valence
    parameters (bond length) of pairs of atoms on the basis of data
    provided in 'Atoms Sizes and Bond Lengths in Molecules and Crystals'
    (O'Keeffe & Brese, 1991).

    Args:
        el_symbol (str): element symbol.
    Returns:
        (dict): atom-size ('r') and electronegativity-related ('c')
                parameter.
    """

    el = Element(el_symbol)
    if el not in list(BV_PARAMS.keys()):
        raise RuntimeError("Could not find O'Keeffe parameters for element"
                           " \"{}\" in \"BV_PARAMS\"dictonary"
                           " provided by pymatgen".format(el_symbol))

    return BV_PARAMS[el]


Instruction:
How would you explain what the following Python 3 function does
def get_okeeffe_distance_prediction(el1, el2):
    el1_okeeffe_params = get_okeeffe_params(el1)
    el2_okeeffe_params = get_okeeffe_params(el2)

    r1 = el1_okeeffe_params['r']
    r2 = el2_okeeffe_params['r']
    c1 = el1_okeeffe_params['c']
    c2 = el2_okeeffe_params['c']

    return r1 + r2 - r1 * r2 * pow(
        sqrt(c1) - sqrt(c2), 2) / (c1 * r1 + c2 * r2)

Response: Returns an estimate of the bond valence parameter for the given element.


Instruction:
How would you implement a function in Python 3 that
returns the neighbors of a given site using a specific neighbor - finding method.

Response:
def get_neighbors_of_site_with_index(struct, n, approach="min_dist", delta=0.1, \
                                     cutoff=10.0):
    """
    Returns the neighbors of a given site using a specific neighbor-finding
    method.

    Args:
        struct (Structure): input structure.
        n (int): index of site in Structure object for which motif type
                is to be determined.
        approach (str): type of neighbor-finding approach, where
              "min_dist" will use the MinimumDistanceNN class,
              "voronoi" the VoronoiNN class, "min_OKeeffe" the
              MinimumOKeeffe class, and "min_VIRE" the MinimumVIRENN class.
        delta (float): tolerance involved in neighbor finding.
        cutoff (float): (large) radius to find tentative neighbors.

    Returns: neighbor sites.
    """

    if approach == "min_dist":
        return MinimumDistanceNN(tol=delta, cutoff=cutoff).get_nn(
            struct, n)
    elif approach == "voronoi":
        return VoronoiNN(tol=delta, cutoff=cutoff).get_nn(
            struct, n)
    elif approach == "min_OKeeffe":
        return MinimumOKeeffeNN(tol=delta, cutoff=cutoff).get_nn(
            struct, n)
    elif approach == "min_VIRE":
        return MinimumVIRENN(tol=delta, cutoff=cutoff).get_nn(
            struct, n)
    else:
        raise RuntimeError("unsupported neighbor-finding method ({}).".format(
            approach))


Instruction:
Implement a Python 3 function for
returning the motif type of the site with index n in structure struct.

Response:
def site_is_of_motif_type(struct, n, approach="min_dist", delta=0.1, \
                          cutoff=10.0, thresh=None):
    """
    Returns the motif type of the site with index n in structure struct;
    currently featuring "tetrahedral", "octahedral", "bcc", and "cp"
    (close-packed: fcc and hcp) as well as "square pyramidal" and
    "trigonal bipyramidal".  If the site is not recognized,
    "unrecognized" is returned.  If a site should be assigned to two
    different motifs, "multiple assignments" is returned.

    Args:
        struct (Structure): input structure.
        n (int): index of site in Structure object for which motif type
                is to be determined.
        approach (str): type of neighbor-finding approach, where
              "min_dist" will use the MinimumDistanceNN class,
              "voronoi" the VoronoiNN class, "min_OKeeffe" the
              MinimumOKeeffe class, and "min_VIRE" the MinimumVIRENN class.
        delta (float): tolerance involved in neighbor finding.
        cutoff (float): (large) radius to find tentative neighbors.
        thresh (dict): thresholds for motif criteria (currently, required
                keys and their default values are "qtet": 0.5,
                "qoct": 0.5, "qbcc": 0.5, "q6": 0.4).

    Returns: motif type (str).
    """

    if thresh is None:
        thresh = {
            "qtet": 0.5, "qoct": 0.5, "qbcc": 0.5, "q6": 0.4,
            "qtribipyr": 0.8, "qsqpyr": 0.8}

    ops = LocalStructOrderParams([
        "cn", "tet", "oct", "bcc", "q6", "sq_pyr", "tri_bipyr"])

    neighs_cent = get_neighbors_of_site_with_index(
        struct, n, approach=approach, delta=delta, cutoff=cutoff)
    neighs_cent.append(struct.sites[n])
    opvals = ops.get_order_parameters(
        neighs_cent, len(neighs_cent) - 1, indices_neighs=[
            i for i in range(len(neighs_cent) - 1)])
    cn = int(opvals[0] + 0.5)
    motif_type = "unrecognized"
    nmotif = 0

    if cn == 4 and opvals[1] > thresh["qtet"]:
        motif_type = "tetrahedral"
        nmotif += 1
    if cn == 5 and opvals[5] > thresh["qsqpyr"]:
        motif_type = "square pyramidal"
        nmotif += 1
    if cn == 5 and opvals[6] > thresh["qtribipyr"]:
        motif_type = "trigonal bipyramidal"
        nmotif += 1
    if cn == 6 and opvals[2] > thresh["qoct"]:
        motif_type = "octahedral"
        nmotif += 1
    if cn == 8 and (opvals[3] > thresh["qbcc"] and opvals[1] < thresh["qtet"]):
        motif_type = "bcc"
        nmotif += 1
    if cn == 12 and (opvals[4] > thresh["q6"] and opvals[1] < thresh["q6"] and
                     opvals[2] < thresh["q6"] and opvals[3] < thresh["q6"]):
        motif_type = "cp"
        nmotif += 1

    if nmotif > 1:
        motif_type = "multiple assignments"

    return motif_type


Instruction:
How would you code a function in Python 3 to
return that part of the first input vector that is orthogonal to the second input vector.

Response:
def gramschmidt(vin, uin):
    """
    Returns that part of the first input vector
    that is orthogonal to the second input vector.
    The output vector is not normalized.

    Args:
        vin (numpy array):
            first input vector
        uin (numpy array):
            second input vector
    """

    vin_uin = np.inner(vin, uin)
    uin_uin = np.inner(uin, uin)
    if uin_uin <= 0.0:
        raise ValueError("Zero or negative inner product!")
    return vin - (vin_uin / uin_uin) * uin


Instruction:
Here you have a function in Python 3, explain what it does
def calculate_weighted_avg(bonds):
    minimum_bond = min(bonds)
    weighted_sum = 0.0
    total_sum = 0.0
    for entry in bonds:
        weighted_sum += entry * exp(1 - (entry / minimum_bond) ** 6)
        total_sum += exp(1 - (entry / minimum_bond) ** 6)
    return weighted_sum / total_sum

Response:
Calculates the weighted average bond length given by
    Hoppe s effective coordination number formula.


Instruction:
Make a summary of the following Python 3 code
def radii(self):
        el = [site.species_string for site in self._structure.sites]
        radii_dict = dict(zip(el, self._ionic_radii))
        # print radii_dict
        return radii_dict

Response: Returns a dictionary of ionic radii of elements in the order of sites.


Instruction:
Here you have a function in Python 3, explain what it does
def valences(self):
        el = [site.species_string for site in self._structure.sites]
        valence_dict = dict(zip(el, self._valences))
        return valence_dict

Response: A dictionary of oxidation states of elements in the order of sites.


Instruction:
Write a Python 3 script for
computing ionic radii of elements in all sites in the structure.

Response:
def _get_ionic_radii(self):
        """
        Computes ionic radii of elements for all sites in the structure.
        If valence is zero, atomic radius is used.
        """
        radii = []
        vnn = VoronoiNN()

        def nearest_key(sorted_vals, key):
            i = bisect_left(sorted_vals, key)
            if i == len(sorted_vals):
                return sorted_vals[-1]
            if i == 0:
                return sorted_vals[0]
            before = sorted_vals[i - 1]
            after = sorted_vals[i]
            if after - key < key - before:
                return after
            else:
                return before

        for i in range(len(self._structure.sites)):
            site = self._structure.sites[i]
            if isinstance(site.specie, Element):
                radius = site.specie.atomic_radius
                # Handle elements with no atomic_radius
                # by using calculated values instead.
                if radius is None:
                    radius = site.specie.atomic_radius_calculated
                if radius is None:
                    raise ValueError(
                        "cannot assign radius to element {}".format(
                            site.specie))
                radii.append(radius)
                continue

            el = site.specie.symbol
            oxi_state = int(round(site.specie.oxi_state))
            coord_no = int(round(vnn.get_cn(self._structure, i)))
            try:
                tab_oxi_states = sorted(map(int, _ion_radii[el].keys()))
                oxi_state = nearest_key(tab_oxi_states, oxi_state)
                radius = _ion_radii[el][str(oxi_state)][str(coord_no)]
            except KeyError:
                if vnn.get_cn(self._structure, i) - coord_no > 0:
                    new_coord_no = coord_no + 1
                else:
                    new_coord_no = coord_no - 1
                try:
                    radius = _ion_radii[el][str(oxi_state)][str(new_coord_no)]
                    coord_no = new_coord_no
                except:
                    tab_coords = sorted(
                        map(int, _ion_radii[el][str(oxi_state)].keys()))
                    new_coord_no = nearest_key(tab_coords, coord_no)
                    i = 0
                    for val in tab_coords:
                        if val > coord_no:
                            break
                        i = i + 1
                    if i == len(tab_coords):
                        key = str(tab_coords[-1])
                        radius = _ion_radii[el][str(oxi_state)][key]
                    elif i == 0:
                        key = str(tab_coords[0])
                        radius = _ion_radii[el][str(oxi_state)][key]
                    else:
                        key = str(tab_coords[i - 1])
                        radius1 = _ion_radii[el][str(oxi_state)][key]
                        key = str(tab_coords[i])
                        radius2 = _ion_radii[el][str(oxi_state)][key]
                        radius = (radius1 + radius2) / 2

            # implement complex checks later
            radii.append(radius)
        return radii


Instruction:
Can you generate the documentation for the following Python 3 function
def _get_valences(self):
        try:
            bv = BVAnalyzer()
            self._structure = bv.get_oxi_state_decorated_structure(
                self._structure)
            valences = bv.get_valences(self._structure)
        except:
            try:
                bv = BVAnalyzer(symm_tol=0.0)
                self._structure = bv.get_oxi_state_decorated_structure(
                    self._structure)
                valences = bv.get_valences(self._structure)
            except:
                valences = []
                for site in self._structure.sites:
                    if len(site.specie.common_oxidation_states) > 0:
                        valences.append(site.specie.common_oxidation_states[0])
                    # Handle noble gas species
                    # which have no entries in common_oxidation_states.
                    else:
                        valences.append(0)
                if sum(valences):
                    valences = [0] * self._structure.num_sites
                else:
                    self._structure.add_oxidation_state_by_site(valences)
                # raise

        # el = [site.specie.symbol for site in self._structure.sites]
        # el = [site.species_string for site in self._structure.sites]
        # el = [site.specie for site in self._structure.sites]
        # valence_dict = dict(zip(el, valences))
        # print valence_dict
        return valences

Response: Compute ionic valences of elements in the structure.


Instruction:
Write a Python 3 script to
get coordination number CN of site with index n in structure.

Response:
def get_cn(self, structure, n, use_weights=False):
        """
        Get coordination number, CN, of site with index n in structure.

        Args:
            structure (Structure): input structure.
            n (integer): index of site for which to determine CN.
            use_weights (boolean): flag indicating whether (True)
                to use weights for computing the coordination number
                or not (False, default: each coordinated site has equal
                weight).
        Returns:
            cn (integer or float): coordination number.
        """

        siw = self.get_nn_info(structure, n)
        return sum([e['weight'] for e in siw]) if use_weights else len(siw)


Instruction:
How would you code a function in Python 3 to
get coordination number CN of each element bonded to site with index n in structure.

Response:
def get_cn_dict(self, structure, n, use_weights=False):
        """
        Get coordination number, CN, of each element bonded to site with index n in structure

        Args:
            structure (Structure): input structure
            n (integer): index of site for which to determine CN.
            use_weights (boolean): flag indicating whether (True)
                to use weights for computing the coordination number
                or not (False, default: each coordinated site has equal
                weight).

        Returns:
            cn (dict): dictionary of CN of each element bonded to site
        """

        siw = self.get_nn_info(structure, n)

        cn_dict = {}
        for i in siw:
            site_element = i['site'].species_string
            if site_element not in cn_dict:
                if use_weights:
                    cn_dict[site_element] = i['weight']
                else:
                    cn_dict[site_element] = 1
            else:
                if use_weights:
                    cn_dict[site_element] += i['weight']
                else:
                    cn_dict[site_element] += 1
        return cn_dict


Instruction:
Here you have a function in Python 3, explain what it does
def get_nn(self, structure, n):

        return [e['site'] for e in self.get_nn_info(structure, n)]

Response: Returns the list of sites near neighbors of site with index n in structure.


Instruction:
Can you create a Python 3 function that
returns the weight associated with each near - neighbor of site with index n in structure.

Response:
def get_weights_of_nn_sites(self, structure, n):
        """
        Get weight associated with each near neighbor of site with
        index n in structure.

        Args:
            structure (Structure): input structure.
            n (integer): index of site for which to determine the weights.
        Returns:
            weights (list of floats): near-neighbor weights.
        """

        return [e['weight'] for e in self.get_nn_info(structure, n)]


Instruction:
Make a summary of the following Python 3 code
def get_nn_images(self, structure, n):

        return [e['image'] for e in self.get_nn_info(structure, n)]

Response: Returns the image locations of all near neighbors of site with index n in structure.


Instruction:
How would you explain what the following Python 3 function does
def get_all_nn_info(self, structure):

        return [self.get_nn_info(structure, n) for n in range(len(structure))]

Response: Get a listing of all neighbors for all sites in a structure.


Instruction:
Can you write a function in Python 3 where it
gets a certain nearest neighbor shell for a certain site.

Response:
def get_nn_shell_info(self, structure, site_idx, shell):
        """Get a certain nearest neighbor shell for a certain site.

        Determines all non-backtracking paths through the neighbor network
        computed by `get_nn_info`. The weight is determined by multiplying
        the weight of the neighbor at each hop through the network. For
        example, a 2nd-nearest-neighbor that has a weight of 1 from its
        1st-nearest-neighbor and weight 0.5 from the original site will
        be assigned a weight of 0.5.

        As this calculation may involve computing the nearest neighbors of
        atoms multiple times, the calculation starts by computing all of the
        neighbor info and then calling `_get_nn_shell_info`. If you are likely
        to call this method for more than one site, consider calling `get_all_nn`
        first and then calling this protected method yourself.

        Args:
            structure (Structure): Input structure
            site_idx (int): index of site for which to determine neighbor
                information.
            shell (int): Which neighbor shell to retrieve (1 == 1st NN shell)
        Returns:
            list of dictionaries. Each entry in the list is information about
                a certain neighbor in the structure, in the same format as
                `get_nn_info`.
        """

        all_nn_info = self.get_all_nn_info(structure)
        sites = self._get_nn_shell_info(structure, all_nn_info, site_idx, shell)

        # Update the site positions
        #   Did not do this during NN options because that can be slower
        output = []
        for info in sites:
            orig_site = structure[info['site_index']]
            info['site'] = PeriodicSite(orig_site.species,
                                        np.add(orig_site.frac_coords,
                                               info['image']),
                                        structure.lattice,
                                        properties=orig_site.properties)
            output.append(info)
        return output


Instruction:
Explain what the following Python 3 code does
def get_bonded_structure(self, structure, decorate=False):

        # requires optional dependency which is why it's not a top-level import
        from pymatgen.analysis.graphs import StructureGraph

        if decorate:
            # Decorate all sites in the underlying structure
            # with site properties that provides information on the
            # coordination number and coordination pattern based
            # on the (current) structure of this graph.
            order_parameters = [self.get_local_order_parameters(structure, n)
                                for n in range(len(structure))]
            structure.add_site_property('order_parameters', order_parameters)

        sg = StructureGraph.with_local_env_strategy(structure, self)

        return sg

Response:
Returns a BondedStructure object using this NearNeighbor
        class.


Instruction:
How would you explain what the following Python 3 function does
def get_voronoi_polyhedra(self, structure, n):

        # Assemble the list of neighbors used in the tessellation
        #   Gets all atoms within a certain radius
        if self.targets is None:
            targets = structure.composition.elements
        else:
            targets = self.targets
        center = structure[n]

        cutoff = self.cutoff

        # max cutoff is the longest diagonal of the cell + room for noise
        corners = [[1, 1, 1], [-1, 1, 1], [1, -1, 1], [1, 1, -1]]
        d_corners = [np.linalg.norm(structure.lattice.get_cartesian_coords(c))
                     for c in corners]
        max_cutoff = max(d_corners) + 0.01

        while True:
            try:
                neighbors = structure.get_sites_in_sphere(
                    center.coords, cutoff)
                neighbors = [i[0] for i in
                             sorted(neighbors, key=lambda s: s[1])]

                # Run the Voronoi tessellation
                qvoronoi_input = [s.coords for s in neighbors]

                voro = Voronoi(
                    qvoronoi_input)  # can give seg fault if cutoff is too small

                # Extract data about the site in question
                cell_info = self._extract_cell_info(
                    structure, 0, neighbors, targets, voro,
                    self.compute_adj_neighbors)
                break

            except RuntimeError as e:
                if cutoff >= max_cutoff:
                    if e.args and "vertex" in e.args[0]:
                        # pass through the error raised by _extract_cell_info
                        raise e
                    else:
                        raise RuntimeError("Error in Voronoi neighbor finding; "
                                           "max cutoff exceeded")
                cutoff = min(cutoff * 2, max_cutoff + 0.001)
        return cell_info

Response: Returns a dict of sites sharing a common Voronoi facet with the site n mapped to a directory containing statistics about the Voronoi cell.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_all_voronoi_polyhedra(self, structure):

        # Special case: For atoms with 1 site, the atom in the root image is not included
        #   in the get_all_neighbors output. Rather than creating logic to add that atom
        #   to the neighbor list, which requires detecting whether it will be translated
        #   to reside within the unit cell before neighbor detection, it is less complex
        #   to just call the one-by-one operation
        if len(structure) == 1:
            return [self.get_voronoi_polyhedra(structure, 0)]

        # Assemble the list of neighbors used in the tessellation
        if self.targets is None:
            targets = structure.composition.elements
        else:
            targets = self.targets

        # Initialize the list of sites with the atoms in the origin unit cell
        #  The `get_all_neighbors` function returns neighbors for each site's image in the
        #   original unit cell. We start off with these central atoms to ensure they are
        #   included in the tessellation

        sites = [x.to_unit_cell() for x in structure]
        indices = [(i, 0, 0, 0) for i, _ in enumerate(structure)]

        # Get all neighbors within a certain cutoff
        #   Record both the list of these neighbors, and the site indices
        all_neighs = structure.get_all_neighbors(self.cutoff,
                                                 include_index=True,
                                                 include_image=True)
        for neighs in all_neighs:
            sites.extend([x[0] for x in neighs])
            indices.extend([(x[2],) + x[3] for x in neighs])

        # Get the non-duplicates (using the site indices for performance/numerical stability)
        indices = np.array(indices, dtype=np.int)
        indices, uniq_inds = np.unique(indices, return_index=True, axis=0)
        sites = np.array(sites)[uniq_inds]

        # Sort array such that atoms in the root image are first
        #   Exploit the fact that the array is sorted by the unique operation such that
        #   the images associated with atom 0 are first, followed by atom 1, etc.
        root_images, = np.nonzero(np.abs(indices[:, 1:]).max(axis=1) == 0)

        del indices  # Save memory (tessellations can be costly)

        # Run the tessellation
        qvoronoi_input = [s.coords for s in sites]
        voro = Voronoi(qvoronoi_input)

        # Get the information for each neighbor
        return [self._extract_cell_info(structure, i, sites, targets,
                                        voro, self.compute_adj_neighbors)
                for i in root_images.tolist()]

Response: Returns a dict of sites sharing a common Voronoi facet with the site n mapped to a directory containing statistics about the Voronoi facet.


Instruction:
Given the following Python 3 function, write the documentation
def _get_elements(self, site):
        try:
            if isinstance(site.specie, Element):
                return [site.specie]
            return [Element(site.specie)]
        except:
            return site.species.elements

Response:
Get the list of elements for a Site
             site


Instruction:
Can you implement a function in Python 3 that
tests whether a site contains elements in the target list

Response:
def _is_in_targets(self, site, targets):
        """
        Test whether a site contains elements in the target list

        Args:
            site (Site): Site to assess
            targets ([Element]) List of elements
        Returns:
             (boolean) Whether this site contains a certain list of elements
        """
        elems = self._get_elements(site)
        for elem in elems:
            if elem not in targets:
                return False
        return True


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _extract_cell_info(self, structure, site_idx, sites, targets, voro,
                           compute_adj_neighbors=False):
        """Get the information about a certain atom from the results of a tessellation

        Args:
            structure (Structure) - Structure being assessed
            site_idx (int) - Index of the atom in question
            sites ([Site]) - List of all sites in the tessellation
            targets ([Element]) - Target elements
            voro - Output of qvoronoi
            compute_adj_neighbors (boolean) - Whether to compute which neighbors are adjacent
        Returns:
            A dict of sites sharing a common Voronoi facet. Key is facet id
             (not useful) and values are dictionaries containing statistics
             about the facet:
                - site: Pymatgen site
                - solid_angle - Solid angle subtended by face
                - angle_normalized - Solid angle normalized such that the
                    faces with the largest
                - area - Area of the facet
                - face_dist - Distance between site n and the facet
                - volume - Volume of Voronoi cell for this face
                - n_verts - Number of vertices on the facet
                - adj_neighbors - Facet id's for the adjacent neighbors
        """
        # Get the coordinates of every vertex
        all_vertices = voro.vertices

        # Get the coordinates of the central site
        center_coords = sites[site_idx].coords

        # Iterate through all the faces in the tessellation
        results = {}
        for nn, vind in voro.ridge_dict.items():
            # Get only those that include the cite in question
            if site_idx in nn:
                other_site = nn[0] if nn[1] == site_idx else nn[1]
                if -1 in vind:
                    # -1 indices correspond to the Voronoi cell
                    #  missing a face
                    if self.allow_pathological:
                        continue
                    else:
                        raise RuntimeError("This structure is pathological,"
                                           " infinite vertex in the voronoi "
                                           "construction")

                # Get the solid angle of the face
                facets = [all_vertices[i] for i in vind]
                angle = solid_angle(center_coords, facets)

                # Compute the volume of associated with this face
                volume = 0
                #  qvoronoi returns vertices in CCW order, so I can break
                #   the face up in to segments (0,1,2), (0,2,3), ... to compute
                #   its area where each number is a vertex size
                for j, k in zip(vind[1:], vind[2:]):
                    volume += vol_tetra(center_coords,
                                        all_vertices[vind[0]],
                                        all_vertices[j],
                                        all_vertices[k])

                # Compute the distance of the site to the face
                face_dist = np.linalg.norm(
                    center_coords - sites[other_site].coords) / 2

                # Compute the area of the face (knowing V=Ad/3)
                face_area = 3 * volume / face_dist

                # Compute the normal of the facet
                normal = np.subtract(sites[other_site].coords, center_coords)
                normal /= np.linalg.norm(normal)

                # Store by face index
                results[other_site] = {
                    'site': sites[other_site],
                    'normal': normal,
                    'solid_angle': angle,
                    'volume': volume,
                    'face_dist': face_dist,
                    'area': face_area,
                    'n_verts': len(vind)
                }

                # If we are computing which neighbors are adjacent, store the vertices
                if compute_adj_neighbors:
                    results[other_site]['verts'] = vind

        # Get only target elements
        resultweighted = {}
        for nn_index, nstats in results.items():
            # Check if this is a target site
            nn = nstats['site']
            if nn.is_ordered:
                if nn.specie in targets:
                    resultweighted[nn_index] = nstats
            else:  # is nn site is disordered
                for disordered_sp in nn.species.keys():
                    if disordered_sp in targets:
                        resultweighted[nn_index] = nstats

        # If desired, determine which neighbors are adjacent
        if compute_adj_neighbors:
            # Initialize storage for the adjacent neighbors
            adj_neighbors = dict((i, []) for i in resultweighted.keys())

            # Find the neighbors that are adjacent by finding those
            #  that contain exactly two vertices
            for a_ind, a_nninfo in resultweighted.items():
                # Get the indices for this site
                a_verts = set(a_nninfo['verts'])

                # Loop over all neighbors that have an index lower that this one
                #  The goal here is to exploit the fact that neighbor adjacency is symmetric
                #  (if A is adj to B, B is adj to A)
                for b_ind, b_nninfo in resultweighted.items():
                    if b_ind > a_ind:
                        continue
                    if len(a_verts.intersection(b_nninfo['verts'])) == 2:
                        adj_neighbors[a_ind].append(b_ind)
                        adj_neighbors[b_ind].append(a_ind)

            # Store the results in the nn_info
            for key, neighbors in adj_neighbors.items():
                resultweighted[key]['adj_neighbors'] = neighbors

        return resultweighted

Response: Extract the information about a certain atom from the results of a tessellation of a Voronoi cell.


Instruction:
Explain what the following Python 3 code does
def get_nn_info(self, structure, n):

        # Run the tessellation
        nns = self.get_voronoi_polyhedra(structure, n)

        # Extract the NN info
        return self._extract_nn_info(structure, nns)

Response:
Get all near - neighbor sites as well as the associated image locations and weights of the site with index n in structure
       .


Instruction:
Given the following Python 3 function, write the documentation
def _extract_nn_info(self, structure, nns):

        # Get the target information
        if self.targets is None:
            targets = structure.composition.elements
        else:
            targets = self.targets

        # Extract the NN info
        siw = []
        max_weight = max(nn[self.weight] for nn in nns.values())
        for nstats in nns.values():
            site = nstats['site']
            if nstats[self.weight] > self.tol * max_weight \
                    and self._is_in_targets(site, targets):
                nn_info = {'site': site,
                           'image': self._get_image(structure, site),
                           'weight': nstats[self.weight] / max_weight,
                           'site_index': self._get_original_site(
                               structure, site)}

                if self.extra_nn_info:
                    # Add all the information about the site
                    poly_info = nstats
                    del poly_info['site']
                    nn_info['poly_info'] = poly_info
                siw.append(nn_info)
        return siw

Response:
Given Voronoi NNs extract the NN info in the form needed by NearestNeighbors
           .


Instruction:
Make a summary of the following Python 3 code
def get_max_bond_distance(self, el1_sym, el2_sym):
        return sqrt(
            (self.el_radius[el1_sym] + self.el_radius[el2_sym] + self.tol) ** 2)

Response: This function returns the maximum bond length from the atomic parameters of the atom 1 and atom 2.


Instruction:
Create a Python 3 function to
return a list of tuples each site and image location and weight of the site with index n.

Response:
def get_nn_info(self, structure, n):
        """
        Get all near-neighbor sites as well as the associated image locations
        and weights of the site with index n using the bond identification
        algorithm underlying Jmol.

        Args:
            structure (Structure): input structure.
            n (integer): index of site for which to determine near
                neighbors.

        Returns:
            siw (list of tuples (Site, array, float)): tuples, each one
                of which represents a neighbor site, its image location,
                and its weight.
        """

        site = structure[n]

        # Determine relevant bond lengths based on atomic radii table
        bonds = {}
        for el in structure.composition.elements:
            bonds[site.specie, el] = self.get_max_bond_distance(
                site.specie.symbol, el.symbol)

        # Search for neighbors up to max bond length + tolerance
        max_rad = max(bonds.values()) + self.tol
        min_rad = min(bonds.values())

        siw = []
        for neighb, dist in structure.get_neighbors(site, max_rad):
            # Confirm neighbor based on bond length specific to atom pair
            if dist <= (bonds[(site.specie, neighb.specie)]) and (
                    dist > self.min_bond_distance):
                weight = min_rad / dist
                siw.append({'site': neighb,
                            'image': self._get_image(structure, neighb),
                            'weight': weight,
                            'site_index': self._get_original_site(structure,
                                                                  neighb)})
        return siw


Instruction:
Can you generate the documentation for the following Python 3 function
def get_nn_info(self, structure, n):

        site = structure[n]
        neighs_dists = structure.get_neighbors(site, self.cutoff)

        siw = []
        if self.get_all_sites == True:
            for s, dist in neighs_dists:
                    w = dist
                    siw.append({'site': s,
                                'image': self._get_image(structure, s),
                                'weight': w,
                                'site_index': self._get_original_site(structure,
                                                                  s)})
        else:
            min_dist = min([dist for neigh, dist in neighs_dists])
            for s, dist in neighs_dists:
                if dist < (1.0 + self.tol) * min_dist:
                    w = min_dist / dist
                    siw.append({'site': s,
                                'image': self._get_image(structure, s),
                                'weight': w,
                                'site_index': self._get_original_site(structure,
                                                                  s)})
        return siw

Response:
Get all near - neighbor sites as well as the associated image locations
        and weights of the site with index n using the closest neighbor
MimeType method.


Instruction:
Explain what the following Python 3 code does
def get_nn_info(self, structure, n):

        from pymatgen.io.babel import BabelMolAdaptor

        obmol = BabelMolAdaptor(structure).openbabel_mol

        siw = []

        # Get only the atom of interest
        site_atom = [a for i, a in enumerate(ob.OBMolAtomDFSIter(obmol))
                     if [a.GetX(), a.GetY(), a.GetZ()] == list(
                structure[n].coords)][0]

        for neighbor in ob.OBAtomAtomIter(site_atom):
            coords = [neighbor.GetX(), neighbor.GetY(), neighbor.GetZ()]
            site = [a for a in structure if list(a.coords) == coords][0]
            index = structure.index(site)

            bond = site_atom.GetBond(neighbor)

            if self.order:
                obmol.PerceiveBondOrders()
                weight = bond.GetBondOrder()
            else:
                weight = bond.GetLength()

            siw.append({"site": site,
                        "image": (0, 0, 0),
                        "weight": weight,
                        "site_index": index})

        return siw

Response: Get all near - neighbor sites and weights of bonds for a given site n.


Instruction:
Can you write a function in Python 3 where it
returns a MoleculeGraph object that is bonded by the given structure.

Response:
def get_bonded_structure(self, structure, decorate=False):
        """
        Obtain a MoleculeGraph object using this NearNeighbor
        class. Requires the optional dependency networkx
        (pip install networkx).

        Args:
            structure: Molecule object.
            decorate (bool): whether to annotate site properties
            with order parameters using neighbors determined by
            this NearNeighbor class

        Returns: a pymatgen.analysis.graphs.MoleculeGraph object
        """

        # requires optional dependency which is why it's not a top-level import
        from pymatgen.analysis.graphs import MoleculeGraph

        if decorate:
            # Decorate all sites in the underlying structure
            # with site properties that provides information on the
            # coordination number and coordination pattern based
            # on the (current) structure of this graph.
            order_parameters = [self.get_local_order_parameters(structure, n)
                                for n in range(len(structure))]
            structure.add_site_property('order_parameters', order_parameters)

        mg = MoleculeGraph.with_local_env_strategy(structure, self)

        return mg


Instruction:
Given the following Python 3 function, write the documentation
def get_nn_shell_info(self, structure, site_idx, shell):

        all_nn_info = self.get_all_nn_info(structure)
        sites = self._get_nn_shell_info(structure, all_nn_info, site_idx, shell)

        # Update the site positions
        #   Did not do this during NN options because that can be slower
        output = []
        for info in sites:
            orig_site = structure[info['site_index']]
            info['site'] = Site(orig_site.species,
                                orig_site._coords,
                                properties=orig_site.properties)
            output.append(info)
        return output

Response: Get a certain nearest neighbor shell for a certain site.


Instruction:
Explain what the following Python 3 code does
def get_nn_info(self, structure, n):

        # This is unfortunately inefficient, but is the best way to fit the
        # current NearNeighbors scheme
        self.bonds = structure.get_covalent_bonds(tol=self.tol)

        siw = []

        for bond in self.bonds:
            capture_bond = False
            if bond.site1 == structure[n]:
                site = bond.site2
                capture_bond = True
            elif bond.site2 == structure[n]:
                site = bond.site1
                capture_bond = True

            if capture_bond:
                index = structure.index(site)
                if self.order:
                    weight = bond.get_bond_order()
                else:
                    weight = bond.length

                siw.append({"site": site,
                            "image": (0, 0, 0),
                            "weight": weight,
                            "site_index": index})

        return siw

Response: Get all near - neighbor sites and weights of a given atom.


Instruction:
Can you tell what is the following Python 3 function doing
def get_nn_info(self, structure, n):

        site = structure[n]
        neighs_dists = structure.get_neighbors(site, self.cutoff)
        try:
            eln = site.specie.element
        except:
            eln = site.species_string

        reldists_neighs = []
        for neigh, dist in neighs_dists:
            try:
                el2 = neigh.specie.element
            except:
                el2 = neigh.species_string
            reldists_neighs.append([dist / get_okeeffe_distance_prediction(
                eln, el2), neigh])

        siw = []
        min_reldist = min([reldist for reldist, neigh in reldists_neighs])
        for reldist, s in reldists_neighs:
            if reldist < (1.0 + self.tol) * min_reldist:
                w = min_reldist / reldist
                siw.append({'site': s,
                            'image': self._get_image(structure, s),
                            'weight': w,
                            'site_index': self._get_original_site(structure,
                                                                  s)})

        return siw

Response: Returns a list of tuples each site and image location and weight of the site with index n.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_nn_info(self, structure, n):

        vire = ValenceIonicRadiusEvaluator(structure)
        site = vire.structure[n]
        neighs_dists = vire.structure.get_neighbors(site, self.cutoff)
        rn = vire.radii[vire.structure[n].species_string]

        reldists_neighs = []
        for neigh, dist in neighs_dists:
            reldists_neighs.append([dist / (
                    vire.radii[neigh.species_string] + rn), neigh])

        siw = []
        min_reldist = min([reldist for reldist, neigh in reldists_neighs])
        for reldist, s in reldists_neighs:
            if reldist < (1.0 + self.tol) * min_reldist:
                w = min_reldist / reldist
                siw.append({'site': s,
                            'image': self._get_image(vire.structure, s),
                            'weight': w,
                            'site_index': self._get_original_site(
                                vire.structure, s)})

        return siw

Response: Get all near - neighbor sites as well as the associated image locations and weights of the site with index n using the closest relative ionic radius - based method with VIRE atomic - radii.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def compute_trigonometric_terms(self, thetas, phis):

        """"
        Computes trigonometric terms that are required to
        calculate bond orientational order parameters using
        internal variables.

        Args:
            thetas ([float]): polar angles of all neighbors in radians.
            phis ([float]): azimuth angles of all neighbors in radians.
                The list of
                azimuth angles of all neighbors in radians.  The list of
                azimuth angles is expected to have the same size as the
                list of polar angles; otherwise, a ValueError is raised.
                Also, the two lists of angles have to be coherent in
                order. That is, it is expected that the order in the list
                of azimuth angles corresponds to a distinct sequence of
                neighbors. And, this sequence has to equal the sequence
                of neighbors in the list of polar angles.

        """

        if len(thetas) != len(phis):
            raise ValueError("List of polar and azimuthal angles have to be"
                             " equal!")

        self._pow_sin_t.clear()
        self._pow_cos_t.clear()
        self._sin_n_p.clear()
        self._cos_n_p.clear()

        self._pow_sin_t[1] = [sin(float(t)) for t in thetas]
        self._pow_cos_t[1] = [cos(float(t)) for t in thetas]
        self._sin_n_p[1] = [sin(float(p)) for p in phis]
        self._cos_n_p[1] = [cos(float(p)) for p in phis]

        for i in range(2, self._max_trig_order + 1):
            self._pow_sin_t[i] = [e[0] * e[1] for e in zip(
                self._pow_sin_t[i - 1], self._pow_sin_t[1])]
            self._pow_cos_t[i] = [e[0] * e[1] for e in zip(
                self._pow_cos_t[i - 1], self._pow_cos_t[1])]
            self._sin_n_p[i] = [sin(float(i) * float(p)) \
                                for p in phis]
            self._cos_n_p[i] = [cos(float(i) * float(p)) \
                                for p in phis]

Response: This function calculates the trigonometric terms that are required to be used to generate the bond orientational order parameters for the current object.


Instruction:
Given the following Python 3 function, write the documentation
def get_q2(self, thetas=None, phis=None):

        """
        Calculates the value of the bond orientational order parameter of
        weight l=2.  If the function is called with non-empty lists of
        polar and azimuthal angles the corresponding trigonometric terms
        are computed afresh.  Otherwise, it is expected that the
        compute_trigonometric_terms function has been just called.

        Args:
            thetas ([float]): polar angles of all neighbors in radians.
            phis ([float]): azimuth angles of all neighbors in radians.

        Returns:
            float: bond orientational order parameter of weight l=2
                corresponding to the input angles thetas and phis.
        """

        if thetas is not None and phis is not None:
            self.compute_trigonometric_terms(thetas, phis)
        nnn = len(self._pow_sin_t[1])
        nnn_range = range(nnn)

        sqrt_15_2pi = sqrt(15.0 / (2.0 * pi))
        sqrt_5_pi = sqrt(5.0 / pi)

        pre_y_2_2 = [0.25 * sqrt_15_2pi * val for val in self._pow_sin_t[2]]
        pre_y_2_1 = [0.5 * sqrt_15_2pi * val[0] * val[1]
                     for val in zip(self._pow_sin_t[1], self._pow_cos_t[1])]

        acc = 0.0

        # Y_2_-2
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_2_2[i] * self._cos_n_p[2][i]
            imag -= pre_y_2_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        # Y_2_-1
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_2_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_2_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_2_0
        real = imag = 0.0
        for i in nnn_range:
            real += 0.25 * sqrt_5_pi * (3.0 * self._pow_cos_t[2][i] - 1.0)
        acc += (real * real)

        # Y_2_1
        real = imag = 0.0
        for i in nnn_range:
            real -= pre_y_2_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_2_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_2_2
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_2_2[i] * self._cos_n_p[2][i]
            imag += pre_y_2_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        q2 = sqrt(4.0 * pi * acc / (5.0 * float(nnn * nnn)))
        return q2

Response: Calculates the value of the bond orientational order parameter of the entry of the class 2.


Instruction:
Write a Python 3 function for
calculating the value of the bond orientational order parameter of the internal system of the acquisition system.

Response:
def get_q4(self, thetas=None, phis=None):

        """
        Calculates the value of the bond orientational order parameter of
        weight l=4.  If the function is called with non-empty lists of
        polar and azimuthal angles the corresponding trigonometric terms
        are computed afresh.  Otherwise, it is expected that the
        compute_trigonometric_terms function has been just called.

        Args:
            thetas ([float]): polar angles of all neighbors in radians.
            phis ([float]): azimuth angles of all neighbors in radians.

        Returns:
            float: bond orientational order parameter of weight l=4
                corresponding to the input angles thetas and phis.
        """

        if thetas is not None and phis is not None:
            self.compute_trigonometric_terms(thetas, phis)
        nnn = len(self._pow_sin_t[1])
        nnn_range = range(nnn)

        i16_3 = 3.0 / 16.0
        i8_3 = 3.0 / 8.0

        sqrt_35_pi = sqrt(35.0 / pi)
        sqrt_35_2pi = sqrt(35.0 / (2.0 * pi))
        sqrt_5_pi = sqrt(5.0 / pi)
        sqrt_5_2pi = sqrt(5.0 / (2.0 * pi))
        sqrt_1_pi = sqrt(1.0 / pi)

        pre_y_4_4 = [i16_3 * sqrt_35_2pi * val for val in self._pow_sin_t[4]]
        pre_y_4_3 = [i8_3 * sqrt_35_pi * val[0] * val[1] \
                     for val in zip(self._pow_sin_t[3], self._pow_cos_t[1])]
        pre_y_4_2 = [i8_3 * sqrt_5_2pi * val[0] * (7.0 * val[1] - 1.0) \
                     for val in zip(self._pow_sin_t[2], self._pow_cos_t[2])]
        pre_y_4_1 = [i8_3 * sqrt_5_pi * val[0] * (7.0 * val[1] - 3.0 * val[2]) \
                     for val in zip(self._pow_sin_t[1], self._pow_cos_t[3], \
                                    self._pow_cos_t[1])]

        acc = 0.0

        # Y_4_-4
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_4[i] * self._cos_n_p[4][i]
            imag -= pre_y_4_4[i] * self._sin_n_p[4][i]
        acc += (real * real + imag * imag)

        # Y_4_-3
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_3[i] * self._cos_n_p[3][i]
            imag -= pre_y_4_3[i] * self._sin_n_p[3][i]
        acc += (real * real + imag * imag)

        # Y_4_-2
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_2[i] * self._cos_n_p[2][i]
            imag -= pre_y_4_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        # Y_4_-1
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_4_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_4_0
        real = imag = 0.0
        for i in nnn_range:
            real += i16_3 * sqrt_1_pi * (35.0 * self._pow_cos_t[4][i] - \
                                         30.0 * self._pow_cos_t[2][i] + 3.0)
        acc += (real * real)

        # Y_4_1
        real = imag = 0.0
        for i in nnn_range:
            real -= pre_y_4_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_4_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_4_2
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_2[i] * self._cos_n_p[2][i]
            imag += pre_y_4_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        # Y_4_3
        real = imag = 0.0
        for i in nnn_range:
            real -= pre_y_4_3[i] * self._cos_n_p[3][i]
            imag -= pre_y_4_3[i] * self._sin_n_p[3][i]
        acc += (real * real + imag * imag)

        # Y_4_4
        real = imag = 0.0
        for i in nnn_range:
            real += pre_y_4_4[i] * self._cos_n_p[4][i]
            imag += pre_y_4_4[i] * self._sin_n_p[4][i]
        acc += (real * real + imag * imag)

        q4 = sqrt(4.0 * pi * acc / (9.0 * float(nnn * nnn)))
        return q4


Instruction:
Can you tell what is the following Python 3 function doing
def get_q6(self, thetas=None, phis=None):

        """
        Calculates the value of the bond orientational order parameter of
        weight l=6.  If the function is called with non-empty lists of
        polar and azimuthal angles the corresponding trigonometric terms
        are computed afresh.  Otherwise, it is expected that the
        compute_trigonometric_terms function has been just called.

        Args:
            thetas ([float]): polar angles of all neighbors in radians.
            phis ([float]): azimuth angles of all neighbors in radians.

        Returns:
            float: bond orientational order parameter of weight l=6
                corresponding to the input angles thetas and phis.
        """

        if thetas is not None and phis is not None:
            self.compute_trigonometric_terms(thetas, phis)
        nnn = len(self._pow_sin_t[1])
        nnn_range = range(nnn)

        i64 = 1.0 / 64.0
        i32 = 1.0 / 32.0
        i32_3 = 3.0 / 32.0
        i16 = 1.0 / 16.0

        sqrt_3003_pi = sqrt(3003.0 / pi)
        sqrt_1001_pi = sqrt(1001.0 / pi)
        sqrt_91_2pi = sqrt(91.0 / (2.0 * pi))
        sqrt_1365_pi = sqrt(1365.0 / pi)
        sqrt_273_2pi = sqrt(273.0 / (2.0 * pi))
        sqrt_13_pi = sqrt(13.0 / pi)

        pre_y_6_6 = [i64 * sqrt_3003_pi * val for val in self._pow_sin_t[6]]
        pre_y_6_5 = [i32_3 * sqrt_1001_pi * val[0] * val[1]
                     for val in zip(self._pow_sin_t[5], self._pow_cos_t[1])]
        pre_y_6_4 = [i32_3 * sqrt_91_2pi * val[0] * (11.0 * val[1] - 1.0)
                     for val in zip(self._pow_sin_t[4], self._pow_cos_t[2])]
        pre_y_6_3 = [
            i32 * sqrt_1365_pi * val[0] * (11.0 * val[1] - 3.0 * val[2])
            for val in zip(self._pow_sin_t[3], self._pow_cos_t[3],
                           self._pow_cos_t[1])]
        pre_y_6_2 = [i64 * sqrt_1365_pi * val[0] * (33.0 * val[1] -
                                                    18.0 * val[2] + 1.0) for val
                     in zip(self._pow_sin_t[2],
                            self._pow_cos_t[4], self._pow_cos_t[2])]
        pre_y_6_1 = [i16 * sqrt_273_2pi * val[0] * (33.0 * val[1] -
                                                    30.0 * val[2] + 5.0 * val[
                                                        3]) for val in
                     zip(self._pow_sin_t[1],
                         self._pow_cos_t[5], self._pow_cos_t[3],
                         self._pow_cos_t[1])]

        acc = 0.0

        # Y_6_-6
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_6[i] * self._cos_n_p[6][i]  # cos(x) =  cos(-x)
            imag -= pre_y_6_6[i] * self._sin_n_p[6][i]  # sin(x) = -sin(-x)
        acc += (real * real + imag * imag)

        # Y_6_-5
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_5[i] * self._cos_n_p[5][i]
            imag -= pre_y_6_5[i] * self._sin_n_p[5][i]
        acc += (real * real + imag * imag)

        # Y_6_-4
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_4[i] * self._cos_n_p[4][i]
            imag -= pre_y_6_4[i] * self._sin_n_p[4][i]
        acc += (real * real + imag * imag)

        # Y_6_-3
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_3[i] * self._cos_n_p[3][i]
            imag -= pre_y_6_3[i] * self._sin_n_p[3][i]
        acc += (real * real + imag * imag)

        # Y_6_-2
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_2[i] * self._cos_n_p[2][i]
            imag -= pre_y_6_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        # Y_6_-1
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_6_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_6_0
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += i32 * sqrt_13_pi * (231.0 * self._pow_cos_t[6][i] -
                                        315.0 * self._pow_cos_t[4][i] + 105.0 *
                                        self._pow_cos_t[2][i] - 5.0)
        acc += (real * real)

        # Y_6_1
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real -= pre_y_6_1[i] * self._cos_n_p[1][i]
            imag -= pre_y_6_1[i] * self._sin_n_p[1][i]
        acc += (real * real + imag * imag)

        # Y_6_2
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_2[i] * self._cos_n_p[2][i]
            imag += pre_y_6_2[i] * self._sin_n_p[2][i]
        acc += (real * real + imag * imag)

        # Y_6_3
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real -= pre_y_6_3[i] * self._cos_n_p[3][i]
            imag -= pre_y_6_3[i] * self._sin_n_p[3][i]
        acc += (real * real + imag * imag)

        # Y_6_4
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_4[i] * self._cos_n_p[4][i]
            imag += pre_y_6_4[i] * self._sin_n_p[4][i]
        acc += (real * real + imag * imag)

        # Y_6_5
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real -= pre_y_6_5[i] * self._cos_n_p[5][i]
            imag -= pre_y_6_5[i] * self._sin_n_p[5][i]
        acc += (real * real + imag * imag)

        # Y_6_6
        real = 0.0
        imag = 0.0
        for i in nnn_range:
            real += pre_y_6_6[i] * self._cos_n_p[6][i]
            imag += pre_y_6_6[i] * self._sin_n_p[6][i]
        acc += (real * real + imag * imag)

        q6 = sqrt(4.0 * pi * acc / (13.0 * float(nnn * nnn)))
        return q6

Response: Calculates the value of the bond orientational order parameter of the specified polar and azimuthal angles.


Instruction:
How would you implement a function in Python 3 that
returns the type of order parameter at the index provided and represented by a short string.

Response:
def get_type(self, index):

        """
        Return type of order parameter at the index provided and
        represented by a short string.

        Args:
            index (int): index of order parameter for which type is
                to be returned.
        Returns:
            str: OP type.
        """
        if index < 0 or index >= len(self._types):
            raise ValueError("Index for getting order parameter type"
                             " out-of-bounds!")
        return self._types[index]


Instruction:
Create a Python 3 function for
returning the list of floats that represents the parameters associated with the order parameter calculation of the order parameter that was defined at the index.

Response:
def get_parameters(self, index):

        """
        Returns list of floats that represents
        the parameters associated
        with calculation of the order
        parameter that was defined at the index provided.
        Attention: the parameters do not need to equal those originally
        inputted because of processing out of efficiency reasons.

        Args:
            index (int):
                index of order parameter for which associated parameters
                are to be returned.
        Returns:
            [float]: parameters of a given OP.
        """
        if index < 0 or index >= len(self._types):
            raise ValueError("Index for getting parameters associated with"
                             " order parameter calculation out-of-bounds!")
        return self._params[index]