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

        def similar_defect(a):
            """
            Used to filter out similar defects of different charges which
            are defined by the same type and location
            """
            return (a.name, a.site)

        # Limits for search
        # E_fermi = { -1 eV to band gap+1}
        # the 1 eV padding provides
        # E_formation. = { -21 eV to 20 eV}
        limits = [[-1, self.band_gap + 1], [-21, 20]]

        stable_entries = {}
        finished_charges = {}
        transition_level_map = {}

        # Grouping by defect types
        for _, defects in groupby(sorted(self.entries, key=similar_defect), similar_defect):
            defects = list(defects)

            # prepping coefficient matrix forx half-space intersection
            # [-Q, 1, -1*(E_form+Q*VBM)] -> -Q*E_fermi+E+-1*(E_form+Q*VBM) <= 0  where E_fermi and E are the variables in the hyperplanes
            hyperplanes = np.array(
                [[-1.0 * entry.charge, 1, -1.0 * (entry.energy + entry.charge * self.vbm)] for entry in defects])

            border_hyperplanes = [[-1, 0, limits[0][0]], [1, 0, -1 * limits[0][1]], [0, -1, limits[1][0]],
                                  [0, 1, -1 * limits[1][1]]]
            hs_hyperplanes = np.vstack([hyperplanes, border_hyperplanes])

            interior_point = [self.band_gap / 2, -20]

            hs_ints = HalfspaceIntersection(hs_hyperplanes, np.array(interior_point))

            # Group the intersections and coresponding facets
            ints_and_facets = zip(hs_ints.intersections, hs_ints.dual_facets)
            # Only inlcude the facets corresponding to entries, not the boundaries
            total_entries = len(defects)
            ints_and_facets = filter(lambda int_and_facet: all(np.array(int_and_facet[1]) < total_entries),
                                     ints_and_facets)
            # sort based on transition level
            ints_and_facets = list(sorted(ints_and_facets, key=lambda int_and_facet: int_and_facet[0][0]))

            if len(ints_and_facets):
                # Unpack into lists
                _, facets = zip(*ints_and_facets)
                # Map of transition level: charge states

                transition_level_map[defects[0].name] = {
                    intersection[0]: [defects[i].charge for i in facet]
                    for intersection, facet in ints_and_facets
                }

                stable_entries[defects[0].name] = list(set([defects[i] for dual in facets for i in dual]))

                finished_charges[defects[0].name] = [defect.charge for defect in defects]
            else:
                # if ints_and_facets is empty, then there is likely only one defect...
                if len(defects) != 1:
                    raise ValueError("ints and facets was empty but more than one defect exists... why?")

                transition_level_map[defects[0].name] = {}

                stable_entries[defects[0].name] = list([defects[0]])

                finished_charges[defects[0].name] = [defects[0].charge]

        self.transition_level_map = transition_level_map
        self.transition_levels = {
            defect_name: list(defect_tls.keys())
            for defect_name, defect_tls in transition_level_map.items()
        }
        self.stable_entries = stable_entries
        self.finished_charges = finished_charges
        self.stable_charges = {
            defect_name: [entry.charge for entry in entries]
            for defect_name, entries in stable_entries.items()
        }

Response: This function finds the stable charges and transition states for a series of defect entries.


Instruction:
Explain what the following Python 3 code does
def all_unstable_entries(self):
        all_stable_entries = self.all_stable_entries
        return [e for e in self.entries if e not in all_stable_entries]

Response: List all unstable entries in the DefectPhaseDiagram


Instruction:
Create a Python 3 function to
return a list of dictionaries of defect concentrations for all stable entries in the DefectPhaseDiagram that are in the same order as the chemical potentials in the VBM.

Response:
def defect_concentrations(self, chemical_potentials, temperature=300, fermi_level=0.):
        """
        Give list of all concentrations at specified efermi in the DefectPhaseDiagram
        args:
            chemical_potentials = {Element: number} is dictionary of chemical potentials to provide formation energies for
            temperature = temperature to produce concentrations from
            fermi_level: (float) is fermi level relative to valence band maximum
                Default efermi = 0 = VBM energy
        returns:
            list of dictionaries of defect concentrations
        """
        concentrations = []
        for dfct in self.all_stable_entries:
            concentrations.append({
                'conc':
                dfct.defect_concentration(
                    chemical_potentials=chemical_potentials, temperature=temperature, fermi_level=fermi_level),
                'name':
                dfct.name,
                'charge':
                dfct.charge
            })

        return concentrations


Instruction:
Make a summary of the following Python 3 code
def suggest_charges(self, tolerance=0.1):
        recommendations = {}

        for def_type in self.defect_types:
            test_charges = np.arange(
                np.min(self.stable_charges[def_type]) - 1,
                np.max(self.stable_charges[def_type]) + 2)
            test_charges = [charge for charge in test_charges if charge not in self.finished_charges[def_type]]

            if len(self.transition_level_map[def_type].keys()):
                # More positive charges will shift the minimum transition level down
                # Max charge is limited by this if its transition level is close to VBM
                min_tl = min(self.transition_level_map[def_type].keys())
                if min_tl < tolerance:
                    max_charge = max(self.transition_level_map[def_type][min_tl])
                    test_charges = [charge for charge in test_charges if charge < max_charge]

                # More negative charges will shift the maximum transition level up
                # Minimum charge is limited by this if transition level is near CBM
                max_tl = max(self.transition_level_map[def_type].keys())
                if max_tl > (self.band_gap - tolerance):
                    min_charge = min(self.transition_level_map[def_type][max_tl])
                    test_charges = [charge for charge in test_charges if charge > min_charge]
            else:
                test_charges = [charge for charge in test_charges if charge not in self.stable_charges[def_type]]

            recommendations[def_type] = test_charges

        return recommendations

Response:
Suggest possible charges for defects to computee based on proximity
MimeType of known transitions from entires to VBM and CBM.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def solve_for_fermi_energy(self, temperature, chemical_potentials, bulk_dos):

        fdos = FermiDos(bulk_dos, bandgap=self.band_gap)

        def _get_total_q(ef):

            qd_tot = sum([
                d['charge'] * d['conc']
                for d in self.defect_concentrations(
                    chemical_potentials=chemical_potentials, temperature=temperature, fermi_level=ef)
            ])
            qd_tot += fdos.get_doping(fermi=ef + self.vbm, T=temperature)
            return qd_tot

        return bisect(_get_total_q, -1., self.band_gap + 1.)

Response:
Solve for the Fermi energy self - consistently as a function of T
        and p_O22
       .


Instruction:
Here you have a function in Python 3, explain what it does
def asxc(cls, obj):
        if isinstance(obj, cls): return obj
        if is_string(obj): return cls.from_name(obj)
        raise TypeError("Don't know how to convert <%s:%s> to Xcfunc" % (type(obj), str(obj)))

Response: Convert object into Xcfunc.


Instruction:
Here you have a function in Python 3, explain what it does
def from_abinit_ixc(cls, ixc):
        ixc = int(ixc)
        if ixc >= 0:
            return cls(**cls.abinitixc_to_libxc[ixc])
        else:
            # libxc notation employed in Abinit: a six-digit number in the form XXXCCC or CCCXXX
            #ixc = str(ixc)
            #assert len(ixc[1:]) == 6
            #first, last = ixc[1:4], ixc[4:]
            ixc = abs(ixc)
            first = ixc // 1000
            last = ixc - first * 1000
            x, c = LibxcFunc(int(first)), LibxcFunc(int(last))
            if not x.is_x_kind: x, c = c, x  # Swap
            assert x.is_x_kind and c.is_c_kind
            return cls(x=x, c=c)

Response: Build the object from an Abinit ixc number.


Instruction:
How would you code a function in Python 3 to
build the object from the type and name.

Response:
def from_type_name(cls, typ, name):
        """Build the object from (type, name)."""
        # Try aliases first.
        for k, nt in cls.defined_aliases.items():
            if typ is not None and typ != nt.type: continue
            #print(name, nt.name)
            if name == nt.name:
                if len(k) == 1: return cls(xc=k)
                if len(k) == 2: return cls(x=k[0], c=k[1])
                raise ValueError("Wrong key: %s" % k)

        # At this point, we should have something in the form
        # name="GGA_X_PBE+GGA_C_PBE" or  name=""LDA_XC_TETER93"
        if "+" in name:
            #if typ is not None: raise ValueError("typ: `%s` but name: `%s`" % (typ, name))
            x, c = (s.strip() for s in name.split("+"))
            x, c = LibxcFunc[x], LibxcFunc[c]
            return cls(x=x, c=c)
        else:
            #if typ is not None: raise ValueError("typ: `%s` but name: `%s`" % (typ, name))
            xc = LibxcFunc[name]
            return cls(xc=xc)

        if typ is None:
            raise ValueError("Cannot find name=%s in defined_aliases" % name)
        else:
            raise ValueError("Cannot find type=%s, name=%s in defined_aliases" % (typ, name))


Instruction:
Here you have a function in Python 3, explain what it does
def from_dict(cls, d):
        return cls(xc=d.get("xc"), x=d.get("x"), c=d.get("c"))

Response: Create a new XcFunc from a dictionary.


Instruction:
Make a summary of the following Python 3 code
def as_dict(self):
        d = {"@module": self.__class__.__module__,
             "@class": self.__class__.__name__}
        # print("in as_dict", type(self.x), type(self.c), type(self.xc))
        if self.x is not None: d["x"] = self.x.as_dict()
        if self.c is not None: d["c"] = self.c.as_dict()
        if self.xc is not None: d["xc"] = self.xc.as_dict()
        return d

Response: Returns a dictionary representation of the object.


Instruction:
Here you have a function in Python 3, explain what it does
def type(self):
        if self.xc in self.defined_aliases: return self.defined_aliases[self.xc].type
        xc = (self.x, self.c)
        if xc in self.defined_aliases: return self.defined_aliases[xc].type

        # If self is not in defined_aliases, use LibxcFunc family
        if self.xc is not None: return self.xc.family
        return "+".join([self.x.family, self.c.family])

Response: The type of the functional.


Instruction:
Explain what the following Python 3 code does
def name(self):
        if self.xc in self.defined_aliases: return self.defined_aliases[self.xc].name
        xc = (self.x, self.c)
        if xc in self.defined_aliases: return self.defined_aliases[xc].name
        if self.xc is not None: return self.xc.name
        return "+".join([self.x.name, self.c.name])

Response: Returns the name of the functional.


Instruction:
How would you implement a function in Python 3 that
returns a list of VoronoiContainer objects from a BSON - encoded list of voronoi objects and a structure.

Response:
def from_bson_voronoi_list(bson_nb_voro_list, structure):
    """
    Returns the voronoi_list needed for the VoronoiContainer object from a bson-encoded voronoi_list (composed of
    vlist and bson_nb_voro_list).
    :param vlist: List of voronoi objects
    :param bson_nb_voro_list: List of periodic sites involved in the Voronoi
    :return: The voronoi_list needed for the VoronoiContainer (with PeriodicSites as keys of the dictionary - not
    allowed in the BSON format)
    """
    voronoi_list = [None] * len(bson_nb_voro_list)
    for isite, voro in enumerate(bson_nb_voro_list):
        if voro is None or voro == 'None':
            continue
        voronoi_list[isite] = []
        for psd, dd in voro:
            struct_site = structure[dd['index']]
            periodic_site = PeriodicSite(struct_site._species, struct_site.frac_coords + psd[1],
                                         struct_site._lattice, properties=struct_site.properties)
            voronoi_list[isite].append((periodic_site, dd))
    return voronoi_list


Instruction:
Explain what the following Python 3 code does
def setup_voronoi_list(self, indices, voronoi_cutoff):
        self.voronoi_list2 = [None] * len(self.structure)
        self.voronoi_list_coords = [None] * len(self.structure)
        logging.info('Getting all neighbors in structure')
        struct_neighbors = self.structure.get_all_neighbors(voronoi_cutoff, include_index=True)
        t1 = time.clock()
        logging.info('Setting up Voronoi list :')

        for jj, isite in enumerate(indices):
            logging.info('  - Voronoi analysis for site #{:d} ({:d}/{:d})'.format(isite, jj+1, len(indices)))
            site = self.structure[isite]
            neighbors1 = [(site, 0.0, isite)]
            neighbors1.extend(struct_neighbors[isite])
            distances = [i[1] for i in sorted(neighbors1, key=lambda s: s[1])]
            neighbors = [i[0] for i in sorted(neighbors1, key=lambda s: s[1])]
            qvoronoi_input = [s.coords for s in neighbors]
            voro = Voronoi(points=qvoronoi_input, qhull_options="o Fv")
            all_vertices = voro.vertices

            results2 = []
            maxangle = 0.0
            mindist = 10000.0
            for iridge, ridge_points in enumerate(voro.ridge_points):
                if 0 in ridge_points:
                    ridge_vertices_indices = voro.ridge_vertices[iridge]
                    if -1 in ridge_vertices_indices:
                        raise RuntimeError("This structure is pathological,"
                                           " infinite vertex in the voronoi "
                                           "construction")

                    ridge_point2 = max(ridge_points)
                    facets = [all_vertices[i] for i in ridge_vertices_indices]
                    sa = my_solid_angle(site.coords, facets)
                    maxangle = max([sa, maxangle])

                    mindist = min([mindist, distances[ridge_point2]])
                    for iii, sss in enumerate(self.structure):
                        if neighbors[ridge_point2].is_periodic_image(sss):
                            myindex = iii
                            break
                    results2.append({'site': neighbors[ridge_point2],
                                     'angle': sa,
                                     'distance': distances[ridge_point2],
                                     'index': myindex})
            for dd in results2:
                dd['normalized_angle'] = dd['angle'] / maxangle
                dd['normalized_distance'] = dd['distance'] / mindist
            self.voronoi_list2[isite] = results2
            self.voronoi_list_coords[isite] = np.array([dd['site'].coords for dd in results2])
        t2 = time.clock()
        logging.info('Voronoi list set up in {:.2f} seconds'.format(t2-t1))

Response: This function sets up the voronoi list of neighbours by calling qhull for each site in the structure.


Instruction:
Here you have a function in Python 3, explain what it does
def setup_neighbors_distances_and_angles(self, indices):
        self.neighbors_distances = [None] * len(self.structure)
        self.neighbors_normalized_distances = [None] * len(self.structure)
        self.neighbors_angles = [None] * len(self.structure)
        self.neighbors_normalized_angles = [None] * len(self.structure)
        for isite in indices:
            results = self.voronoi_list2[isite]
            if results is None:
                continue
            #Initializes neighbors distances and normalized distances groups
            self.neighbors_distances[isite] = []
            self.neighbors_normalized_distances[isite] = []
            normalized_distances = [nb_dict['normalized_distance'] for nb_dict in results]
            isorted_distances = np.argsort(normalized_distances)
            self.neighbors_normalized_distances[isite].append({'min': normalized_distances[isorted_distances[0]],
                                                               'max': normalized_distances[isorted_distances[0]]})
            self.neighbors_distances[isite].append({'min': results[isorted_distances[0]]['distance'],
                                                    'max': results[isorted_distances[0]]['distance']})
            icurrent = 0
            nb_indices = {int(isorted_distances[0])}
            dnb_indices = {int(isorted_distances[0])}
            for idist in iter(isorted_distances):
                wd = normalized_distances[idist]
                if self.maximum_distance_factor is not None:
                    if wd > self.maximum_distance_factor:
                        self.neighbors_normalized_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                        self.neighbors_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                        self.neighbors_normalized_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                        self.neighbors_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                        break
                if np.isclose(wd, self.neighbors_normalized_distances[isite][icurrent]['max'],
                              rtol=0.0, atol=self.normalized_distance_tolerance):
                    self.neighbors_normalized_distances[isite][icurrent]['max'] = wd
                    self.neighbors_distances[isite][icurrent]['max'] = results[idist]['distance']
                    dnb_indices.add(int(idist))
                else:
                    self.neighbors_normalized_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                    self.neighbors_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                    self.neighbors_normalized_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                    self.neighbors_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                    dnb_indices = {int(idist)}
                    self.neighbors_normalized_distances[isite].append({'min': wd,
                                                                       'max': wd})
                    self.neighbors_distances[isite].append({'min': results[idist]['distance'],
                                                            'max': results[idist]['distance']})
                    icurrent += 1
                nb_indices.add(int(idist))
            else:
                self.neighbors_normalized_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                self.neighbors_distances[isite][icurrent]['nb_indices'] = list(nb_indices)
                self.neighbors_normalized_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                self.neighbors_distances[isite][icurrent]['dnb_indices'] = list(dnb_indices)
            for idist in range(len(self.neighbors_distances[isite]) - 1):
                dist_dict = self.neighbors_distances[isite][idist]
                dist_dict_next = self.neighbors_distances[isite][idist+1]
                dist_dict['next'] = dist_dict_next['min']
                ndist_dict = self.neighbors_normalized_distances[isite][idist]
                ndist_dict_next = self.neighbors_normalized_distances[isite][idist + 1]
                ndist_dict['next'] = ndist_dict_next['min']
            if self.maximum_distance_factor is not None:
                dfact = self.maximum_distance_factor
            else:
                dfact = self.default_voronoi_cutoff / self.neighbors_distances[isite][0]['min']
            self.neighbors_normalized_distances[isite][-1]['next'] = dfact
            self.neighbors_distances[isite][-1]['next'] = dfact * self.neighbors_distances[isite][0]['min']
            #Initializes neighbors angles and normalized angles groups
            self.neighbors_angles[isite] = []
            self.neighbors_normalized_angles[isite] = []
            normalized_angles = [nb_dict['normalized_angle'] for nb_dict in results]
            isorted_angles = np.argsort(normalized_angles)[::-1]
            self.neighbors_normalized_angles[isite].append({'max': normalized_angles[isorted_angles[0]],
                                                            'min': normalized_angles[isorted_angles[0]]})
            self.neighbors_angles[isite].append({'max': results[isorted_angles[0]]['angle'],
                                                 'min': results[isorted_angles[0]]['angle']})
            icurrent = 0
            nb_indices = {int(isorted_angles[0])}
            dnb_indices = {int(isorted_angles[0])}
            for iang in iter(isorted_angles):
                wa = normalized_angles[iang]
                if self.minimum_angle_factor is not None:
                    if wa < self.minimum_angle_factor:
                        self.neighbors_normalized_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                        self.neighbors_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                        self.neighbors_normalized_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                        self.neighbors_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                        break
                if np.isclose(wa, self.neighbors_normalized_angles[isite][icurrent]['min'],
                              rtol=0.0, atol=self.normalized_angle_tolerance):
                    self.neighbors_normalized_angles[isite][icurrent]['min'] = wa
                    self.neighbors_angles[isite][icurrent]['min'] = results[iang]['angle']
                    dnb_indices.add(int(iang))
                else:
                    self.neighbors_normalized_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                    self.neighbors_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                    self.neighbors_normalized_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                    self.neighbors_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                    dnb_indices = {int(iang)}
                    self.neighbors_normalized_angles[isite].append({'max': wa,
                                                                    'min': wa})
                    self.neighbors_angles[isite].append({'max': results[iang]['angle'],
                                                         'min': results[iang]['angle']})
                    icurrent += 1
                nb_indices.add(int(iang))
            else:
                self.neighbors_normalized_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                self.neighbors_angles[isite][icurrent]['nb_indices'] = list(nb_indices)
                self.neighbors_normalized_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
                self.neighbors_angles[isite][icurrent]['dnb_indices'] = list(dnb_indices)
            for iang in range(len(self.neighbors_angles[isite]) - 1):
                ang_dict = self.neighbors_angles[isite][iang]
                ang_dict_next = self.neighbors_angles[isite][iang + 1]
                ang_dict['next'] = ang_dict_next['max']
                nang_dict = self.neighbors_normalized_angles[isite][iang]
                nang_dict_next = self.neighbors_normalized_angles[isite][iang + 1]
                nang_dict['next'] = nang_dict_next['max']
            if self.minimum_angle_factor is not None:
                afact = self.minimum_angle_factor
            else:
                afact = 0.0
            self.neighbors_normalized_angles[isite][-1]['next'] = afact
            self.neighbors_angles[isite][-1]['next'] = afact * self.neighbors_angles[isite][0]['max']

Response: Initializes the angle and distance separations for neighbors.


Instruction:
Write a Python 3 script to
transform the voronoi_list into a vlist + bson_nb_voro_list that are BSON - encodable.

Response:
def to_bson_voronoi_list2(self):
        """
        Transforms the voronoi_list into a vlist + bson_nb_voro_list, that are BSON-encodable.
        :return: [vlist, bson_nb_voro_list], to be used in the as_dict method
        """
        bson_nb_voro_list2 = [None] * len(self.voronoi_list2)
        for ivoro, voro in enumerate(self.voronoi_list2):
            if voro is None or voro == 'None':
                continue
            site_voro = []
            # {'site': neighbors[nn[1]],
            #  'angle': sa,
            #  'distance': distances[nn[1]],
            #  'index': myindex}
            for nb_dict in voro:
                site = nb_dict['site']
                site_dict = {key: val for key, val in nb_dict.items() if key not in ['site']}
                #site_voro.append([ps.as_dict(), dd]) [float(c) for c in self.frac_coords]
                diff = site.frac_coords - self.structure[nb_dict['index']].frac_coords
                site_voro.append([[nb_dict['index'], [float(c) for c in diff]],
                                  site_dict])
            bson_nb_voro_list2[ivoro] = site_voro
        return bson_nb_voro_list2


Instruction:
Here you have a function in Python 3, explain what it does
def as_dict(self):
        bson_nb_voro_list2 = self.to_bson_voronoi_list2()
        return {"@module": self.__class__.__module__,
                "@class": self.__class__.__name__,
                "bson_nb_voro_list2": bson_nb_voro_list2,
                # "neighbors_lists": self.neighbors_lists,
                "structure": self.structure.as_dict(),
                "normalized_angle_tolerance": self.normalized_angle_tolerance,
                "normalized_distance_tolerance": self.normalized_distance_tolerance,
                "additional_conditions": self.additional_conditions,
                "valences": self.valences,
                "maximum_distance_factor": self.maximum_distance_factor,
                "minimum_angle_factor": self.minimum_angle_factor}

Response: Returns a dictionary representation of the VoronoiContainer.


Instruction:
Can you generate the documentation for the following Python 3 function
def from_dict(cls, d):
        structure = Structure.from_dict(d['structure'])
        voronoi_list2 = from_bson_voronoi_list2(d['bson_nb_voro_list2'], structure)
        maximum_distance_factor = d['maximum_distance_factor'] if 'maximum_distance_factor' in d else None
        minimum_angle_factor = d['minimum_angle_factor'] if 'minimum_angle_factor' in d else None
        return cls(structure=structure, voronoi_list2=voronoi_list2,
                   # neighbors_lists=neighbors_lists,
                   normalized_angle_tolerance=d['normalized_angle_tolerance'],
                   normalized_distance_tolerance=d['normalized_distance_tolerance'],
                   additional_conditions=d['additional_conditions'],
                   valences=d['valences'],
                   maximum_distance_factor=maximum_distance_factor,
                   minimum_angle_factor=minimum_angle_factor)

Response: Reconstructs the VoronoiContainer object from a dictionary representation of the VoronoiContainer object.


Instruction:
Can you implement a function in Python 3 that
saves the id of the last node created.

Response:
def save_lastnode_id():
    """Save the id of the last node created."""
    init_counter()

    with FileLock(_COUNTER_FILE):
        with AtomicFile(_COUNTER_FILE, mode="w") as fh:
            fh.write("%d\n" % _COUNTER)


Instruction:
Explain what the following Python 3 code does
def as_status(cls, obj):
        if obj is None: return None
        return obj if isinstance(obj, cls) else cls.from_string(obj)

Response: Convert obj into a Status.


Instruction:
How would you explain what the following Python 3 function does
def from_string(cls, s):
        for num, text in cls._STATUS2STR.items():
            if text == s:
                return cls(num)
        else:
            raise ValueError("Wrong string %s" % s)

Response: Return a Status instance from its string representation.


Instruction:
Create a Python 3 function for
listing of output files produces by self.

Response:
def products(self):
        """List of output files produces by self."""
        _products = []
        for ext in self.exts:
            prod = Product(ext, self.node.opath_from_ext(ext))
            _products.append(prod)

        return _products


Instruction:
Can you generate the documentation for the following Python 3 function
def apply_getters(self, task):
        if not self.getters: return

        for getter in self.getters:
            if getter == "@structure":
                task.history.info("Getting structure from %s" % self.node)
                new_structure = self.node.get_final_structure()
                task._change_structure(new_structure)
            else:
                raise ValueError("Wrong getter %s" % getter)

Response: Applies the getters to the task.


Instruction:
How would you explain what the following Python 3 function does
def connecting_vars(self):
        vars = {}
        for prod in self.products:
            vars.update(prod.connecting_vars())

        return vars

Response:
Returns a dictionary with the variables that must be added to the the
        input file in order to connect this node to its dependencies.


Instruction:
How would you code a function in Python 3 to
return the paths of the output files produced by this object and its extensions

Response:
def get_filepaths_and_exts(self):
        """Returns the paths of the output files produced by self and its extensions"""
        filepaths = [prod.filepath for prod in self.products]
        exts = [prod.ext for prod in self.products]

        return filepaths, exts


Instruction:
Write a Python 3 script to
build a : class:`Product instance from a filepath.

Response:
def from_file(cls, filepath):
        """Build a :class:`Product` instance from a filepath."""
        # Find the abinit extension.
        for i in range(len(filepath)):
            if filepath[i:] in abi_extensions():
                ext = filepath[i:]
                break
        else:
            raise ValueError("Cannot detect abinit extension in %s" % filepath)

        return cls(ext, filepath)


Instruction:
Make a summary of the following Python 3 code
def from_node(cls, node):
        kwargs = dict(
            node_id=node.node_id,
            node_finalized=node.finalized,
            node_history=list(node.history),
            node_name=node.name,
            node_class=node.__class__.__name__,
            node_status=str(node.status),
        )

        return node.Results(node, **kwargs)

Response: Initialize an instance of NodeResults from a Node subclass.


Instruction:
Can you generate the documentation for the following Python 3 function
def update_collection(self, collection):
        node = self.node
        flow = node if node.is_flow else node.flow

        # Build the key used to store the entry in the document.
        key = node.name
        if node.is_task:
            key = "w" + str(node.pos[0]) + "_t" + str(node.pos[1])
        elif node.is_work:
            key = "w" + str(node.pos)

        db = collection.database

        # Save files with GridFs first in order to get the ID.
        if self.gridfs_files:
            import gridfs
            fs = gridfs.GridFS(db)
            for ext, gridfile in self.gridfs_files.items():
                logger.info("gridfs: about to put file:", str(gridfile))
                # Here we set gridfile.fs_id that will be stored in the mondodb document
                try:
                    with open(gridfile.path, "r" + gridfile.mode) as f:
                        gridfile.fs_id = fs.put(f, filename=gridfile.path)
                except IOError as exc:
                    logger.critical(str(exc))

        if flow.mongo_id is None:
            # Flow does not have a mongo_id, allocate doc for the flow and save its id.
            flow.mongo_id = collection.insert({})
            print("Creating flow.mongo_id", flow.mongo_id, type(flow.mongo_id))

        # Get the document from flow.mongo_id and update it.
        doc = collection.find_one({"_id": flow.mongo_id})
        if key in doc:
            raise ValueError("%s is already in doc!" % key)
        doc[key] = self.as_dict()

        collection.save(doc)

Response: Update a mongodb collection with the current entry.


Instruction:
Can you generate the documentation for the following Python 3 function
def color_hex(self):
        def clamp(x):
            return max(0, min(int(x), 255))

        r, g, b = np.trunc(self.color_rgb * 255)
        return "#{0:02x}{1:02x}{2:02x}".format(clamp(r), clamp(g), clamp(b))

Response: Node color as Hex Triplet https://en. wikidata. org.


Instruction:
Explain what the following Python 3 code does
def isinstance(self, class_or_string):
        if class_or_string is None:
            return False
        import inspect
        if inspect.isclass(class_or_string):
            return isinstance(self, class_or_string)
        else:
            return self.__class__.__name__.lower() == class_or_string.lower()

Response: Check whether the node is an instance of class_or_string.


Instruction:
Explain what the following Python 3 code does
def as_node(cls, obj):
        if isinstance(obj, cls):
            return obj
        elif is_string(obj):
            # Assume filepath.
            return FileNode(obj)
        elif obj is None:
            return obj
        else:
            raise TypeError("Don't know how to convert %s to Node instance." % obj)

Response: Convert obj into a Node instance.


Instruction:
Create a Python 3 function to
return the name of the node.

Response:
def name(self):
        """
        The name of the node
        (only used for facilitating its identification in the user interface).
        """
        try:
            return self._name
        except AttributeError:
            if self.is_task:
                try:
                    return self.pos_str
                except:
                    return os.path.basename(self.workdir)
            else:
                return os.path.basename(self.workdir)


Instruction:
Can you implement a function in Python 3 that
returns a relative version of the workdir

Response:
def relworkdir(self):
        """Return a relative version of the workdir"""
        if getattr(self, "workdir", None) is None:
            return None
        try:
            return os.path.relpath(self.workdir)
        except OSError:
            # current working directory may not be defined!
            return self.workdir


Instruction:
Can you tell what is the following Python 3 function doing
def log_correction(self, event, action):
        # TODO: Create CorrectionObject
        action = str(action)
        self.history.info(action)

        self._corrections.append(dict(
            event=event.as_dict(),
            action=action,
        ))

Response: This method is called when we have fixed the problem associated with this event. It adds a new entry to the correction history.


Instruction:
How would you implement a function in Python 3 that
adds a list of dependencies to the node.

Response:
def add_deps(self, deps):
        """
        Add a list of dependencies to the :class:`Node`.

        Args:
            deps: List of :class:`Dependency` objects specifying the dependencies of the node.
                  or dictionary mapping nodes to file extensions e.g. {task: "DEN"}
        """
        if isinstance(deps, collections.Mapping):
            # Convert dictionary into list of dependencies.
            deps = [Dependency(node, exts) for node, exts in deps.items()]

        # We want a list
        if not isinstance(deps, (list, tuple)):
            deps = [deps]

        assert all(isinstance(d, Dependency) for d in deps)

        # Add the dependencies to the node
        self._deps.extend(deps)

        if self.is_work:
            # The task in the work should inherit the same dependency.
            for task in self:
                task.add_deps(deps)

        # If we have a FileNode as dependency, add self to its children
        # Node.get_parents will use this list if node.is_isfile.
        for dep in (d for d in deps if d.node.is_file):
            dep.node.add_filechild(self)


Instruction:
How would you implement a function in Python 3 that
removes a list of dependencies from the Node.

Response:
def remove_deps(self, deps):
        """
        Remove a list of dependencies from the :class:`Node`.

        Args:
            deps: List of :class:`Dependency` objects specifying the  dependencies of the node.
        """
        if not isinstance(deps, (list, tuple)):
            deps = [deps]

        assert all(isinstance(d, Dependency) for d in deps)

        self._deps = [d for d in self._deps if d not in deps]

        if self.is_work:
            # remove the same list of dependencies from the task in the work
            for task in self:
                task.remove_deps(deps)


Instruction:
Implement a Python 3 function for
returning a list with the status of the dependencies.

Response:
def deps_status(self):
        """Returns a list with the status of the dependencies."""
        if not self.deps:
            return [self.S_OK]

        return [d.status for d in self.deps]


Instruction:
How would you implement a function in Python 3 that
gets the list of nodes that depend on this node.

Response:
def get_children(self):
        """
        Return the list of nodes in the :class:`Flow` that depends on this :class:`Node`

        .. note::

            This routine assumes the entire flow has been allocated.
        """
        # Specialized branch for FileNode.
        if self.is_file:
            return self.filechildren

        # Inspect the entire flow to get children.
        children = []
        for work in self.flow:
            if work.depends_on(self): children.append(work)
            for task in work:
                if task.depends_on(self): children.append(task)
        return children


Instruction:
Given the following Python 3 function, write the documentation
def str_deps(self):
        lines = []
        app = lines.append

        app("Dependencies of node %s:" % str(self))
        for i, dep in enumerate(self.deps):
            app("%d) %s, status=%s" % (i, dep.info, str(dep.status)))

        return "\n".join(lines)

Response: Return the string representation of the dependencies of the node.


Instruction:
Can you create a Python 3 function that
returns pandas DataFrame with the value of the variables specified in varnames.

Response:
def get_vars_dataframe(self, *varnames):
        """
        Return pandas DataFrame with the value of the variables specified in `varnames`.
        Can be used for task/works/flow. It's recursive!

        .. example:

            flow.get_vars_dataframe("ecut", "ngkpt")
            work.get_vars_dataframe("acell", "usepawu")
        """
        import pandas as pd
        if self.is_task:
            df = pd.DataFrame([{v: self.input.get(v, None) for v in varnames}], index=[self.name], columns=varnames)
            df["class"] = self.__class__.__name__
            return df

        elif self.is_work:
            frames = [task.get_vars_dataframe(*varnames) for task in self]
            return pd.concat(frames)

        elif self.is_flow:
            frames = [work.get_vars_dataframe(*varnames) for work in self]
            return pd.concat(frames)

        else:
            #print("Ignoring node of type: `%s`" % type(self))
            return pd.DataFrame(index=[self.name])


Instruction:
Make a summary of the following Python 3 code
def get_graphviz_dirtree(self, engine="automatic", **kwargs):
        if engine == "automatic":
            engine = "fdp"

        return Dirviz(self.workdir).get_cluster_graph(engine=engine, **kwargs)

Response: Generate a directory tree of files and directories in the node workdir.


Instruction:
How would you explain what the following Python 3 function does
def event_handlers(self):
        if self.is_flow:
            return self._event_handlers

        try:
            return self._event_handlers
        except AttributeError:
            return self.flow._event_handlers

Response: Returns a list of handlers registered for this node.


Instruction:
Write a Python 3 function that can
install the EventHandlers for this Node.

Response:
def install_event_handlers(self, categories=None, handlers=None):
        """
        Install the `EventHandlers for this `Node`. If no argument is provided
        the default list of handlers is installed.

        Args:
            categories: List of categories to install e.g. base + can_change_physics
            handlers: explicit list of :class:`EventHandler` instances.
                      This is the most flexible way to install handlers.

        .. note::

            categories and handlers are mutually exclusive.
        """
        if categories is not None and handlers is not None:
            raise ValueError("categories and handlers are mutually exclusive!")

        from .events import get_event_handler_classes
        if categories:
            raise NotImplementedError()
            handlers = [cls() for cls in get_event_handler_classes(categories=categories)]
        else:
            handlers = handlers or [cls() for cls in get_event_handler_classes()]

        self._event_handlers = handlers


Instruction:
Can you implement a function in Python 3 that
prints to stream the event handlers installed for this flow.

Response:
def show_event_handlers(self, stream=sys.stdout, verbose=0):
        """Print to `stream` the event handlers installed for this flow."""
        lines = ["List of event handlers installed:"]
        for handler in self.event_handlers:
            if verbose:
                lines.extend(handler.__class__.cls2str().split("\n"))
            else:
                lines.extend(str(handler).split("\n"))

        stream.write("\n".join(lines))
        stream.write("\n")


Instruction:
How would you implement a function in Python 3 that
sends a signal to all connected receivers unless the node is in spectator mode.

Response:
def send_signal(self, signal):
        """
        Send signal from this node to all connected receivers unless the node is in spectator mode.

        signal -- (hashable) signal value, see `dispatcher` connect for details

        Return a list of tuple pairs [(receiver, response), ... ]
        or None if the node is in spectator mode.

        if any receiver raises an error, the error propagates back
        through send, terminating the dispatch loop, so it is quite
        possible to not have all receivers called if a raises an error.
        """
        if self.in_spectator_mode: return None
        logger.debug("Node %s broadcasts signal %s" % (self, signal))
        dispatcher.send(signal=signal, sender=self)


Instruction:
Create a Python 3 function to
return the message after merging any user - supplied arguments with the message.

Response:
def get_message(self, metadata=False, asctime=True):
        """
        Return the message after merging any user-supplied arguments with the message.

        Args:
            metadata: True if function and module name should be added.
            asctime: True if time string should be added.
        """
        msg = self.msg if is_string(self.msg) else str(self.msg)
        if self.args:
            try:
                msg = msg % self.args
            except:
                msg += str(self.args)

        if asctime: msg = "[" + self.asctime + "] " + msg

        # Add metadata
        if metadata:
            msg += "\nCalled by %s at %s:%s\n" % (self.func_name, self.pathname, self.lineno)

        return msg


Instruction:
Given the following Python 3 function, write the documentation
def to_string(self, metadata=False):
        return "\n".join(rec.get_message(metadata=metadata) for rec in self)

Response: Returns a string with the history.


Instruction:
Create a Python 3 function to
log msg % args with the warning severity level

Response:
def warning(self, msg, *args, **kwargs):
        """Log 'msg % args' with the warning severity level"""
        self._log("WARNING", msg, args, kwargs)


Instruction:
Given the following Python 3 function, write the documentation
def critical(self, msg, *args, **kwargs):
        self._log("CRITICAL", msg, args, kwargs)

Response: Log msg % args with the critical severity level


Instruction:
Implement a function in Python 3 to
low - level logging routine which creates a HistoryRecord.

Response:
def _log(self, level, msg, args, exc_info=None, extra=None):
        """Low-level logging routine which creates a :class:`HistoryRecord`."""
        if exc_info and not isinstance(exc_info, tuple):
            exc_info = sys.exc_info()

        self.append(HistoryRecord(level, "unknown filename", 0, msg, args, exc_info, func="unknown func"))


Instruction:
How would you implement a function in Python 3 that
parses libxc_docs. txt file and return dictionary with mapping libxc_id --> info_dict

Response:
def parse_libxc_docs(path):
    """
    Parse libxc_docs.txt file, return dictionary with mapping:
    libxc_id --> info_dict
    """
    def parse_section(section):
	d = {}
	for l in section:
	    key, value = l.split(":")
	    key = key.strip()
	    d[key] = value.strip()

	return int(d["Number"]), d

    d = OrderedDict()
    with open(path, "rt") as fh:
	section = []
	for line in fh:
	    if not line.startswith("-"):
		section.append(line)
	    else:
		num, entry = parse_section(section)
		assert num not in d
		d[num] = entry
		section = []
	assert not section

    return d


Instruction:
Write a Python 3 function that can
write json file with libxc metadata to path jpath.

Response:
def write_libxc_docs_json(xcfuncs, jpath):
    """Write json file with libxc metadata to path jpath."""
    from copy import deepcopy
    xcfuncs = deepcopy(xcfuncs)

    # Remove XC_FAMILY from Family and XC_ from Kind to make strings more human-readable.
    for d in xcfuncs.values():
        d["Family"] = d["Family"].replace("XC_FAMILY_", "", 1)
        d["Kind"] = d["Kind"].replace("XC_", "", 1)

    # Build lightweight version with a subset of keys.
    for num, d in xcfuncs.items():
        xcfuncs[num] = {k: d[k] for k in ("Family", "Kind", "References")}
        # Descriptions are optional
        for opt in ("Description 1", "Description 2"):
            desc = d.get(opt)
            if desc is not None: xcfuncs[num][opt] = desc

    with open(jpath, "wt") as fh:
        json.dump(xcfuncs, fh)

    return xcfuncs


Instruction:
Can you generate the documentation for the following Python 3 function
def make_movie(structures, output_filename="movie.mp4", zoom=1.0, fps=20,
               bitrate="10000k", quality=1, **kwargs):
    """
    Generate a movie from a sequence of structures using vtk and ffmpeg.

    Args:
        structures ([Structure]): sequence of structures
        output_filename (str): filename for structure output. defaults to
            movie.mp4
        zoom (float): A zoom to be applied to the visualizer. Defaults to 1.0.
        fps (int): Frames per second for the movie. Defaults to 20.
        bitrate (str): Video bitate.  Defaults to "10000k" (fairly high
            quality).
        quality (int): A quality scale. Defaults to 1.
        \\*\\*kwargs: Any kwargs supported by StructureVis to modify the images
            generated.
    """
    vis = StructureVis(**kwargs)
    vis.show_help = False
    vis.redraw()
    vis.zoom(zoom)
    sigfig = int(math.floor(math.log10(len(structures))) + 1)
    filename = "image{0:0" + str(sigfig) + "d}.png"
    for i, s in enumerate(structures):
        vis.set_structure(s)
        vis.write_image(filename.format(i), 3)
    filename = "image%0" + str(sigfig) + "d.png"
    args = ["ffmpeg", "-y", "-i", filename,
            "-q:v", str(quality), "-r", str(fps), "-b:v", str(bitrate),
            output_filename]
    subprocess.Popen(args)

Response: Generate a movie from a sequence of structures using vtk and ffmpeg.


Instruction:
Implement a function in Python 3 to
rotate the camera view.

Response:
def rotate_view(self, axis_ind=0, angle=0):
        """
        Rotate the camera view.

        Args:
            axis_ind: Index of axis to rotate. Defaults to 0, i.e., a-axis.
            angle: Angle to rotate by. Defaults to 0.
        """
        camera = self.ren.GetActiveCamera()
        if axis_ind == 0:
            camera.Roll(angle)
        elif axis_ind == 1:
            camera.Azimuth(angle)
        else:
            camera.Pitch(angle)
        self.ren_win.Render()


Instruction:
Given the following Python 3 function, write the documentation
def write_image(self, filename="image.png", magnification=1,
                    image_format="png"):
        """
        Save render window to an image.

        Arguments:
            filename:
                filename to save to. Defaults to image.png.
            magnification:
                magnification. Use it to render high res images.
            image_format:
                choose between jpeg, png.  Png is the default.
        """
        render_large = vtk.vtkRenderLargeImage()
        render_large.SetInput(self.ren)
        if image_format == "jpeg":
            writer = vtk.vtkJPEGWriter()
            writer.SetQuality(80)
        else:
            writer = vtk.vtkPNGWriter()

        render_large.SetMagnification(magnification)
        writer.SetFileName(filename)

        writer.SetInputConnection(render_large.GetOutputPort())
        self.ren_win.Render()
        writer.Write()
        del render_large

Response: Save render window to an image.


Instruction:
Explain what the following Python 3 code does
def redraw(self, reset_camera=False):
        self.ren.RemoveAllViewProps()
        self.picker = None
        self.add_picker_fixed()
        self.helptxt_mapper = vtk.vtkTextMapper()
        tprops = self.helptxt_mapper.GetTextProperty()
        tprops.SetFontSize(14)
        tprops.SetFontFamilyToTimes()
        tprops.SetColor(0, 0, 0)

        if self.structure is not None:
            self.set_structure(self.structure, reset_camera)

        self.ren_win.Render()

Response: Redraw the render window.


Instruction:
Given the following Python 3 function, write the documentation
def display_help(self):
        helptxt = ["h : Toggle help",
                   "A/a, B/b or C/c : Increase/decrease cell by one a,"
                   " b or c unit vector", "# : Toggle showing of polyhedrons",
                   "-: Toggle showing of bonds", "r : Reset camera direction",
                   "[/]: Decrease or increase poly_radii_tol_factor "
                   "by 0.05. Value = " + str(self.poly_radii_tol_factor),
                   "Up/Down: Rotate view along Up direction by 90 "
                   "clockwise/anticlockwise",
                   "Left/right: Rotate view along camera direction by "
                   "90 clockwise/anticlockwise", "s: Save view to image.png",
                   "o: Orthogonalize structure"]
        self.helptxt_mapper.SetInput("\n".join(helptxt))
        self.helptxt_actor.SetPosition(10, 10)
        self.helptxt_actor.VisibilityOn()

Response: Display the help for various keyboard shortcuts.


Instruction:
Can you tell what is the following Python 3 function doing
def set_structure(self, structure, reset_camera=True, to_unit_cell=True):
        self.ren.RemoveAllViewProps()

        has_lattice = hasattr(structure, "lattice")

        if has_lattice:
            s = Structure.from_sites(structure, to_unit_cell=to_unit_cell)
            s.make_supercell(self.supercell, to_unit_cell=to_unit_cell)
        else:
            s = structure

        inc_coords = []
        for site in s:
            self.add_site(site)
            inc_coords.append(site.coords)

        count = 0
        labels = ["a", "b", "c"]
        colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

        if has_lattice:
            matrix = s.lattice.matrix

        if self.show_unit_cell and has_lattice:
            #matrix = s.lattice.matrix
            self.add_text([0, 0, 0], "o")
            for vec in matrix:
                self.add_line((0, 0, 0), vec, colors[count])
                self.add_text(vec, labels[count], colors[count])
                count += 1
            for (vec1, vec2) in itertools.permutations(matrix, 2):
                self.add_line(vec1, vec1 + vec2)
            for (vec1, vec2, vec3) in itertools.permutations(matrix, 3):
                self.add_line(vec1 + vec2, vec1 + vec2 + vec3)

        if self.show_bonds or self.show_polyhedron:
            elements = sorted(s.composition.elements, key=lambda a: a.X)
            anion = elements[-1]

            def contains_anion(site):
                for sp in site.species.keys():
                    if sp.symbol == anion.symbol:
                        return True
                return False

            anion_radius = anion.average_ionic_radius
            for site in s:
                exclude = False
                max_radius = 0
                color = np.array([0, 0, 0])
                for sp, occu in site.species.items():
                    if sp.symbol in self.excluded_bonding_elements \
                            or sp == anion:
                        exclude = True
                        break
                    max_radius = max(max_radius, sp.average_ionic_radius)
                    color = color + \
                            occu * np.array(self.el_color_mapping.get(sp.symbol,
                                                                      [0, 0, 0]))

                if not exclude:
                    max_radius = (1 + self.poly_radii_tol_factor) * \
                                 (max_radius + anion_radius)
                    nn = structure.get_neighbors(site, float(max_radius))
                    nn_sites = []
                    for nnsite, dist in nn:
                        if contains_anion(nnsite):
                            nn_sites.append(nnsite)
                            if not in_coord_list(inc_coords, nnsite.coords):
                                self.add_site(nnsite)
                    if self.show_bonds:
                        self.add_bonds(nn_sites, site)
                    if self.show_polyhedron:
                        color = [i / 255 for i in color]
                        self.add_polyhedron(nn_sites, site, color)

        if self.show_help:
            self.helptxt_actor = vtk.vtkActor2D()
            self.helptxt_actor.VisibilityOn()
            self.helptxt_actor.SetMapper(self.helptxt_mapper)
            self.ren.AddActor(self.helptxt_actor)
            self.display_help()

        camera = self.ren.GetActiveCamera()
        if reset_camera:
            if has_lattice:
                #Adjust the camera for best viewing
                lengths = s.lattice.abc
                pos = (matrix[1] + matrix[2]) * 0.5 + \
                      matrix[0] * max(lengths) / lengths[0] * 3.5
                camera.SetPosition(pos)
                camera.SetViewUp(matrix[2])
                camera.SetFocalPoint((matrix[0] + matrix[1] + matrix[2]) * 0.5)
            else:
                origin = s.center_of_mass
                max_site = max(
                    s, key=lambda site: site.distance_from_point(origin))
                camera.SetPosition(origin + 5 * (max_site.coords - origin))
                camera.SetFocalPoint(s.center_of_mass)

        self.structure = structure
        self.title = s.composition.formula

Response: Add a structure to the visualizer.


Instruction:
Explain what the following Python 3 code does
def zoom(self, factor):
        camera = self.ren.GetActiveCamera()
        camera.Zoom(factor)
        self.ren_win.Render()

Response: Zoom the camera view by a factor.


Instruction:
Given the following Python 3 function, write the documentation
def add_site(self, site):
        start_angle = 0
        radius = 0
        total_occu = 0

        for specie, occu in site.species.items():
            radius += occu * (specie.ionic_radius
                              if isinstance(specie, Specie)
                                 and specie.ionic_radius
                              else specie.average_ionic_radius)
            total_occu += occu

        vis_radius = 0.2 + 0.002 * radius

        for specie, occu in site.species.items():
            if not specie:
                color = (1, 1, 1)
            elif specie.symbol in self.el_color_mapping:
                color = [i / 255 for i in self.el_color_mapping[specie.symbol]]
            mapper = self.add_partial_sphere(site.coords, vis_radius, color,
                                             start_angle, start_angle + 360 * occu)
            self.mapper_map[mapper] = [site]
            start_angle += 360 * occu

        if total_occu < 1:
            mapper = self.add_partial_sphere(site.coords, vis_radius, (1,1,1),
                                             start_angle, start_angle + 360 * (1 - total_occu))
            self.mapper_map[mapper] = [site]

Response: Adds a site to the render window.


Instruction:
Can you tell what is the following Python 3 function doing
def add_text(self, coords, text, color=(0, 0, 0)):
        source = vtk.vtkVectorText()
        source.SetText(text)
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(source.GetOutputPort())
        follower = vtk.vtkFollower()
        follower.SetMapper(mapper)
        follower.GetProperty().SetColor(color)
        follower.SetPosition(coords)
        follower.SetScale(0.5)
        self.ren.AddActor(follower)
        follower.SetCamera(self.ren.GetActiveCamera())

Response: Add text at a coordinate.


Instruction:
Implement a Python 3 function for
adding a line to the current set of active classes.

Response:
def add_line(self, start, end, color=(0.5, 0.5, 0.5), width=1):
        """
        Adds a line.

        Args:
            start: Starting coordinates for line.
            end: Ending coordinates for line.
            color: Color for text as RGB. Defaults to grey.
            width: Width of line. Defaults to 1.
        """
        source = vtk.vtkLineSource()
        source.SetPoint1(start)
        source.SetPoint2(end)

        vertexIDs = vtk.vtkStringArray()
        vertexIDs.SetNumberOfComponents(1)
        vertexIDs.SetName("VertexIDs")
        # Set the vertex labels
        vertexIDs.InsertNextValue("a")
        vertexIDs.InsertNextValue("b")
        source.GetOutput().GetPointData().AddArray(vertexIDs)

        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(source.GetOutputPort())
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        actor.GetProperty().SetColor(color)
        actor.GetProperty().SetLineWidth(width)
        self.ren.AddActor(actor)


Instruction:
Can you tell what is the following Python 3 function doing
def add_polyhedron(self, neighbors, center, color, opacity=1.0,
                       draw_edges=False, edges_color=[0.0, 0.0, 0.0],
                       edges_linewidth=2):
        """
        Adds a polyhedron.

        Args:
            neighbors: Neighbors of the polyhedron (the vertices).
            center: The atom in the center of the polyhedron.
            color: Color for text as RGB.
            opacity: Opacity of the polyhedron
            draw_edges: If set to True, the a line will be drawn at each edge
            edges_color: Color of the line for the edges
            edges_linewidth: Width of the line drawn for the edges
        """
        points = vtk.vtkPoints()
        conv = vtk.vtkConvexPointSet()
        for i in range(len(neighbors)):
            x, y, z = neighbors[i].coords
            points.InsertPoint(i, x, y, z)
            conv.GetPointIds().InsertId(i, i)
        grid = vtk.vtkUnstructuredGrid()
        grid.Allocate(1, 1)
        grid.InsertNextCell(conv.GetCellType(), conv.GetPointIds())
        grid.SetPoints(points)

        dsm = vtk.vtkDataSetMapper()
        polysites = [center]
        polysites.extend(neighbors)
        self.mapper_map[dsm] = polysites
        if vtk.VTK_MAJOR_VERSION <= 5:
            dsm.SetInputConnection(grid.GetProducerPort())
        else:
            dsm.SetInputData(grid)
        ac = vtk.vtkActor()
        #ac.SetMapper(mapHull)
        ac.SetMapper(dsm)
        ac.GetProperty().SetOpacity(opacity)
        if color == 'element':
            # If partial occupations are involved, the color of the specie with
            # the highest occupation is used
            myoccu = 0.0
            for specie, occu in center.species.items():
                if occu > myoccu:
                    myspecie = specie
                    myoccu = occu
            color = [i / 255 for i in self.el_color_mapping[myspecie.symbol]]
            ac.GetProperty().SetColor(color)
        else:
            ac.GetProperty().SetColor(color)
        if draw_edges:
            ac.GetProperty().SetEdgeColor(edges_color)
            ac.GetProperty().SetLineWidth(edges_linewidth)
            ac.GetProperty().EdgeVisibilityOn()
        self.ren.AddActor(ac)

Response: Adds a polyhedron to the vtkActor.


Instruction:
Here you have a function in Python 3, explain what it does
def add_triangle(self, neighbors, color, center=None, opacity=0.4,
                     draw_edges=False, edges_color=[0.0, 0.0, 0.0],
                     edges_linewidth=2):
        """
        Adds a triangular surface between three atoms.

        Args:
            atoms: Atoms between which a triangle will be drawn.
            color: Color for triangle as RGB.
            center: The "central atom" of the triangle
            opacity: opacity of the triangle
            draw_edges: If set to True, the a line will be  drawn at each edge
            edges_color: Color of the line for the edges
            edges_linewidth: Width of the line drawn for the edges
        """
        points = vtk.vtkPoints()
        triangle = vtk.vtkTriangle()
        for ii in range(3):
            points.InsertNextPoint(neighbors[ii].x, neighbors[ii].y,
                                   neighbors[ii].z)
            triangle.GetPointIds().SetId(ii, ii)
        triangles = vtk.vtkCellArray()
        triangles.InsertNextCell(triangle)

        # polydata object
        trianglePolyData = vtk.vtkPolyData()
        trianglePolyData.SetPoints( points )
        trianglePolyData.SetPolys( triangles )

        # mapper
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInput(trianglePolyData)

        ac = vtk.vtkActor()
        ac.SetMapper(mapper)
        ac.GetProperty().SetOpacity(opacity)
        if color == 'element':
            if center is None:
                raise ValueError(
                    'Color should be chosen according to the central atom, '
                    'and central atom is not provided')
            # If partial occupations are involved, the color of the specie with
            # the highest occupation is used
            myoccu = 0.0
            for specie, occu in center.species.items():
                if occu > myoccu:
                    myspecie = specie
                    myoccu = occu
            color = [i / 255 for i in self.el_color_mapping[myspecie.symbol]]
            ac.GetProperty().SetColor(color)
        else:
            ac.GetProperty().SetColor(color)
        if draw_edges:
            ac.GetProperty().SetEdgeColor(edges_color)
            ac.GetProperty().SetLineWidth(edges_linewidth)
            ac.GetProperty().EdgeVisibilityOn()
        self.ren.AddActor(ac)

Response: Adds a triangle to the current state of the object.


Instruction:
Implement a Python 3 function for
adding bonds to the current site.

Response:
def add_bonds(self, neighbors, center, color=None, opacity=None,
                  radius=0.1):
        """
        Adds bonds for a site.

        Args:
            neighbors: Neighbors of the site.
            center: The site in the center for all bonds.
            color: Color of the tubes representing the bonds
            opacity: Opacity of the tubes representing the bonds
            radius: Radius of tube s representing the bonds
        """
        points = vtk.vtkPoints()
        points.InsertPoint(0, center.x, center.y, center.z)
        n = len(neighbors)
        lines = vtk.vtkCellArray()
        for i in range(n):
            points.InsertPoint(i + 1, neighbors[i].coords)
            lines.InsertNextCell(2)
            lines.InsertCellPoint(0)
            lines.InsertCellPoint(i + 1)
        pd = vtk.vtkPolyData()
        pd.SetPoints(points)
        pd.SetLines(lines)

        tube = vtk.vtkTubeFilter()
        if vtk.VTK_MAJOR_VERSION <= 5:
            tube.SetInputConnection(pd.GetProducerPort())
        else:
            tube.SetInputData(pd)
        tube.SetRadius(radius)

        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(tube.GetOutputPort())

        actor = vtk.vtkActor()
        actor.SetMapper(mapper)
        if opacity is not None:
            actor.GetProperty().SetOpacity(opacity)
        if color is not None:
            actor.GetProperty().SetColor(color)
        self.ren.AddActor(actor)


Instruction:
How would you explain what the following Python 3 function does
def get_rot(slab):
    new_z = get_mi_vec(slab)
    a, b, c = slab.lattice.matrix
    new_x = a / np.linalg.norm(a)
    new_y = np.cross(new_z, new_x)
    x, y, z = np.eye(3)
    rot_matrix = np.array([np.dot(*el) for el in
                           itertools.product([x, y, z],
                                             [new_x, new_y, new_z])]).reshape(3, 3)
    rot_matrix = np.transpose(rot_matrix)
    sop = SymmOp.from_rotation_and_translation(rot_matrix)
    return sop

Response: Gets the transformation to rotate the z axis into the miller index


Instruction:
Can you implement a function in Python 3 that
converts a cartesian coordinate such that it is inside the unit cell.

Response:
def put_coord_inside(lattice, cart_coordinate):
    """
    converts a cartesian coordinate such that it is inside the unit cell.
    """
    fc = lattice.get_fractional_coords(cart_coordinate)
    return lattice.get_cartesian_coords([c - np.floor(c) for c in fc])


Instruction:
Make a summary of the following Python 3 code
def plot_slab(slab, ax, scale=0.8, repeat=5, window=1.5,
              draw_unit_cell=True, decay=0.2, adsorption_sites=True):
    """
    Function that helps visualize the slab in a 2-D plot, for
    convenient viewing of output of AdsorbateSiteFinder.

    Args:
        slab (slab): Slab object to be visualized
        ax (axes): matplotlib axes with which to visualize
        scale (float): radius scaling for sites
        repeat (int): number of repeating unit cells to visualize
        window (float): window for setting the axes limits, is essentially
            a fraction of the unit cell limits
        draw_unit_cell (bool): flag indicating whether or not to draw cell
        decay (float): how the alpha-value decays along the z-axis
    """
    orig_slab = slab.copy()
    slab = reorient_z(slab)
    orig_cell = slab.lattice.matrix.copy()
    if repeat:
        slab.make_supercell([repeat, repeat, 1])
    coords = np.array(sorted(slab.cart_coords, key=lambda x: x[2]))
    sites = sorted(slab.sites, key=lambda x: x.coords[2])
    alphas = 1 - decay * (np.max(coords[:, 2]) - coords[:, 2])
    alphas = alphas.clip(min=0)
    corner = [0, 0, slab.lattice.get_fractional_coords(coords[-1])[-1]]
    corner = slab.lattice.get_cartesian_coords(corner)[:2]
    verts = orig_cell[:2, :2]
    lattsum = verts[0] + verts[1]
    # Draw circles at sites and stack them accordingly
    for n, coord in enumerate(coords):
        r = sites[n].specie.atomic_radius * scale
        ax.add_patch(patches.Circle(coord[:2] - lattsum * (repeat // 2),
                                    r, color='w', zorder=2 * n))
        color = color_dict[sites[n].species_string]
        ax.add_patch(patches.Circle(coord[:2] - lattsum * (repeat // 2), r,
                                    facecolor=color, alpha=alphas[n],
                                    edgecolor='k', lw=0.3, zorder=2 * n + 1))
    # Adsorption sites
    if adsorption_sites:
        asf = AdsorbateSiteFinder(orig_slab)
        ads_sites = asf.find_adsorption_sites()['all']
        sop = get_rot(orig_slab)
        ads_sites = [sop.operate(ads_site)[:2].tolist()
                     for ads_site in ads_sites]
        ax.plot(*zip(*ads_sites), color='k', marker='x',
                markersize=10, mew=1, linestyle='', zorder=10000)
    # Draw unit cell
    if draw_unit_cell:
        verts = np.insert(verts, 1, lattsum, axis=0).tolist()
        verts += [[0., 0.]]
        verts = [[0., 0.]] + verts
        codes = [Path.MOVETO, Path.LINETO, Path.LINETO,
                 Path.LINETO, Path.CLOSEPOLY]
        verts = [(np.array(vert) + corner).tolist() for vert in verts]
        path = Path(verts, codes)
        patch = patches.PathPatch(path, facecolor='none', lw=2,
                                  alpha=0.5, zorder=2 * n + 2)
        ax.add_patch(patch)
    ax.set_aspect("equal")
    center = corner + lattsum / 2.
    extent = np.max(lattsum)
    lim_array = [center - extent * window, center + extent * window]
    x_lim = [ele[0] for ele in lim_array]
    y_lim = [ele[1] for ele in lim_array]
    ax.set_xlim(x_lim)
    ax.set_ylim(y_lim)
    return ax

Response: Function that helps visualize the slab in a 2 - D plot


Instruction:
Make a summary of the following Python 3 code
def from_bulk_and_miller(cls, structure, miller_index, min_slab_size=8.0,
                             min_vacuum_size=10.0, max_normal_search=None,
                             center_slab=True, selective_dynamics=False,
                             undercoord_threshold=0.09):
        """
        This method constructs the adsorbate site finder from a bulk
        structure and a miller index, which allows the surface sites
        to be determined from the difference in bulk and slab coordination,
        as opposed to the height threshold.

        Args:
            structure (Structure): structure from which slab
                input to the ASF is constructed
            miller_index (3-tuple or list): miller index to be used
            min_slab_size (float): min slab size for slab generation
            min_vacuum_size (float): min vacuum size for slab generation
            max_normal_search (int): max normal search for slab generation
            center_slab (bool): whether to center slab in slab generation
            selective dynamics (bool): whether to assign surface sites
                to selective dynamics
            undercoord_threshold (float): threshold of "undercoordation"
                to use for the assignment of surface sites.  Default is
                0.1, for which surface sites will be designated if they
                are 10% less coordinated than their bulk counterpart
        """
        # TODO: for some reason this works poorly with primitive cells
        #       may want to switch the coordination algorithm eventually
        vnn_bulk = VoronoiNN(tol=0.05)
        bulk_coords = [len(vnn_bulk.get_nn(structure, n))
                       for n in range(len(structure))]
        struct = structure.copy(site_properties={'bulk_coordinations': bulk_coords})
        slabs = generate_all_slabs(struct, max_index=max(miller_index),
                                   min_slab_size=min_slab_size,
                                   min_vacuum_size=min_vacuum_size,
                                   max_normal_search=max_normal_search,
                                   center_slab=center_slab)

        slab_dict = {slab.miller_index: slab for slab in slabs}

        if miller_index not in slab_dict:
            raise ValueError("Miller index not in slab dict")

        this_slab = slab_dict[miller_index]

        vnn_surface = VoronoiNN(tol=0.05, allow_pathological=True)

        surf_props, undercoords = [], []
        this_mi_vec = get_mi_vec(this_slab)
        mi_mags = [np.dot(this_mi_vec, site.coords) for site in this_slab]
        average_mi_mag = np.average(mi_mags)
        for n, site in enumerate(this_slab):
            bulk_coord = this_slab.site_properties['bulk_coordinations'][n]
            slab_coord = len(vnn_surface.get_nn(this_slab, n))
            mi_mag = np.dot(this_mi_vec, site.coords)
            undercoord = (bulk_coord - slab_coord) / bulk_coord
            undercoords += [undercoord]
            if undercoord > undercoord_threshold and mi_mag > average_mi_mag:
                surf_props += ['surface']
            else:
                surf_props += ['subsurface']
        new_site_properties = {'surface_properties': surf_props,
                               'undercoords': undercoords}
        new_slab = this_slab.copy(site_properties=new_site_properties)
        return cls(new_slab, selective_dynamics)

Response: This method constructs an adsorbate site finder from a bulk and miller index.


Instruction:
Can you generate the documentation for the following Python 3 function
def find_surface_sites_by_height(self, slab, height=0.9, xy_tol=0.05):

        # Get projection of coordinates along the miller index
        m_projs = np.array([np.dot(site.coords, self.mvec)
                            for site in slab.sites])

        # Mask based on window threshold along the miller index.
        mask = (m_projs - np.amax(m_projs)) >= -height
        surf_sites = [slab.sites[n] for n in np.where(mask)[0]]
        if xy_tol:
            # sort surface sites by height
            surf_sites = [s for (h, s) in zip(m_projs[mask], surf_sites)]
            surf_sites.reverse()
            unique_sites, unique_perp_fracs = [], []
            for site in surf_sites:
                this_perp = site.coords - np.dot(site.coords, self.mvec)
                this_perp_frac = slab.lattice.get_fractional_coords(this_perp)
                if not in_coord_list_pbc(unique_perp_fracs, this_perp_frac):
                    unique_sites.append(site)
                    unique_perp_fracs.append(this_perp_frac)
            surf_sites = unique_sites

        return surf_sites

Response: This method finds the surface sites within a certain distance from the topmost site in a slab by finding which sites are within a certain threshold in angstroms of distance from the topmost site in a list of sites.


Instruction:
How would you explain what the following Python 3 function does
def get_extended_surface_mesh(self, repeat=(5, 5, 1)):
        surf_str = Structure.from_sites(self.surface_sites)
        surf_str.make_supercell(repeat)
        return surf_str

Response:
Returns an extended surface mesh for the adsorption
        site finding by constructing supercell of surface sites and then returning the extended surface mesh.


Instruction:
Given the following Python 3 function, write the documentation
def find_adsorption_sites(self, distance=2.0, put_inside=True,
                              symm_reduce=1e-2, near_reduce=1e-2,
                              positions=['ontop', 'bridge', 'hollow'],
                              no_obtuse_hollow=True):
        """
        Finds surface sites according to the above algorithm.  Returns
        a list of corresponding cartesian coordinates.

        Args:
            distance (float): distance from the coordinating ensemble
                of atoms along the miller index for the site (i. e.
                the distance from the slab itself)
            put_inside (bool): whether to put the site inside the cell
            symm_reduce (float): symm reduction threshold
            near_reduce (float): near reduction threshold
            positions (list): which positions to include in the site finding
                "ontop": sites on top of surface sites
                "bridge": sites at edges between surface sites in Delaunay
                    triangulation of surface sites in the miller plane
                "hollow": sites at centers of Delaunay triangulation faces
                "subsurface": subsurface positions projected into miller plane
            no_obtuse_hollow (bool): flag to indicate whether to include
                obtuse triangular ensembles in hollow sites
        """
        ads_sites = {k: [] for k in positions}
        if 'ontop' in positions:
            ads_sites['ontop'] = [s.coords for s in self.surface_sites]
        if 'subsurface' in positions:
            # Get highest site
            ref = self.slab.sites[np.argmax(self.slab.cart_coords[:, 2])]
            # Project diff between highest site and subs site into miller
            ss_sites = [self.mvec * np.dot(ref.coords - s.coords, self.mvec)
                        + s.coords for s in self.subsurface_sites()]
            ads_sites['subsurface'] = ss_sites
        if 'bridge' in positions or 'hollow' in positions:
            mesh = self.get_extended_surface_mesh()
            sop = get_rot(self.slab)
            dt = Delaunay([sop.operate(m.coords)[:2] for m in mesh])
            # TODO: refactor below to properly account for >3-fold
            for v in dt.simplices:
                if -1 not in v:
                    dots = []
                    for i_corner, i_opp in zip(range(3), ((1, 2), (0, 2), (0, 1))):
                        corner, opp = v[i_corner], [v[o] for o in i_opp]
                        vecs = [mesh[d].coords - mesh[corner].coords for d in opp]
                        vecs = [vec / np.linalg.norm(vec) for vec in vecs]
                        dots.append(np.dot(*vecs))
                        # Add bridge sites at midpoints of edges of D. Tri
                        if 'bridge' in positions:
                            ads_sites["bridge"].append(
                                self.ensemble_center(mesh, opp))
                    # Prevent addition of hollow sites in obtuse triangles
                    obtuse = no_obtuse_hollow and (np.array(dots) < 1e-5).any()
                    # Add hollow sites at centers of D. Tri faces
                    if 'hollow' in positions and not obtuse:
                        ads_sites['hollow'].append(
                            self.ensemble_center(mesh, v))
        ads_sites['all'] = sum(ads_sites.values(), [])
        for key, sites in ads_sites.items():
            # Pare off outer sites for bridge/hollow
            if key in ['bridge', 'hollow']:
                frac_coords = [self.slab.lattice.get_fractional_coords(ads_site)
                               for ads_site in sites]
                frac_coords = [frac_coord for frac_coord in frac_coords
                               if (frac_coord[0] > 1 and frac_coord[0] < 4
                                   and frac_coord[1] > 1 and frac_coord[1] < 4)]
                sites = [self.slab.lattice.get_cartesian_coords(frac_coord)
                         for frac_coord in frac_coords]
            if near_reduce:
                sites = self.near_reduce(sites, threshold=near_reduce)
            if put_inside:
                sites = [put_coord_inside(self.slab.lattice, coord)
                         for coord in sites]
            if symm_reduce:
                sites = self.symm_reduce(sites, threshold=symm_reduce)
            sites = [site + distance * self.mvec for site in sites]

            ads_sites[key] = sites
        return ads_sites

Response: Finds the surface sites of the specified distance from the surface sites of the ensemble and returns a list of corresponding cartesian coordinates.


Instruction:
Write a Python 3 function that can
reduce the set of adsorbate sites by finding duplicates and removing symmetrically equivalent duplicates.

Response:
def symm_reduce(self, coords_set, threshold=1e-6):
        """
        Reduces the set of adsorbate sites by finding removing
        symmetrically equivalent duplicates

        Args:
            coords_set: coordinate set in cartesian coordinates
            threshold: tolerance for distance equivalence, used
                as input to in_coord_list_pbc for dupl. checking
        """
        surf_sg = SpacegroupAnalyzer(self.slab, 0.1)
        symm_ops = surf_sg.get_symmetry_operations()
        unique_coords = []
        # Convert to fractional
        coords_set = [self.slab.lattice.get_fractional_coords(coords)
                      for coords in coords_set]
        for coords in coords_set:
            incoord = False
            for op in symm_ops:
                if in_coord_list_pbc(unique_coords, op.operate(coords),
                                     atol=threshold):
                    incoord = True
                    break
            if not incoord:
                unique_coords += [coords]
        # convert back to cartesian
        return [self.slab.lattice.get_cartesian_coords(coords)
                for coords in unique_coords]


Instruction:
Implement a function in Python 3 to
return a list of unique coordinates that are within threshold.

Response:
def near_reduce(self, coords_set, threshold=1e-4):
        """
        Prunes coordinate set for coordinates that are within
        threshold

        Args:
            coords_set (Nx3 array-like): list or array of coordinates
            threshold (float): threshold value for distance
        """
        unique_coords = []
        coords_set = [self.slab.lattice.get_fractional_coords(coords)
                      for coords in coords_set]
        for coord in coords_set:
            if not in_coord_list_pbc(unique_coords, coord, threshold):
                unique_coords += [coord]
        return [self.slab.lattice.get_cartesian_coords(coords)
                for coords in unique_coords]


Instruction:
Make a summary of the following Python 3 code
def ensemble_center(self, site_list, indices, cartesian=True):
        if cartesian:
            return np.average([site_list[i].coords for i in indices],
                              axis=0)
        else:
            return np.average([site_list[i].frac_coords for i in indices],
                              axis=0)

Response: Returns the center of an ensemble of sites selected from a list of sites.


Instruction:
Make a summary of the following Python 3 code
def add_adsorbate(self, molecule, ads_coord, repeat=None, reorient=True):
        if reorient:
            # Reorient the molecule along slab m_index
            sop = get_rot(self.slab)
            molecule.apply_operation(sop.inverse)
        struct = self.slab.copy()
        if repeat:
            struct.make_supercell(repeat)
        if 'surface_properties' in struct.site_properties.keys():
            molecule.add_site_property("surface_properties",
                                       ["adsorbate"] * molecule.num_sites)
        if 'selective_dynamics' in struct.site_properties.keys():
            molecule.add_site_property("selective_dynamics",
                                       [[True, True, True]] * molecule.num_sites)
        for site in molecule:
            struct.append(site.specie, ads_coord + site.coords, coords_are_cartesian=True,
                          properties=site.properties)
        return struct

Response: Adds an adsorbate at a particular coordinate.


Instruction:
How would you implement a function in Python 3 that
assigns selective dynamics to a slab

Response:
def assign_selective_dynamics(self, slab):
        """
        Helper function to assign selective dynamics site_properties
        based on surface, subsurface site properties

        Args:
            slab (Slab): slab for which to assign selective dynamics
        """
        sd_list = []
        sd_list = [[False, False, False] if site.properties['surface_properties'] == 'subsurface'
                   else [True, True, True] for site in slab.sites]
        new_sp = slab.site_properties
        new_sp['selective_dynamics'] = sd_list
        return slab.copy(site_properties=new_sp)


Instruction:
Can you write a function in Python 3 where it
functions that generates all adsorption structures for a given molecular adsorbate. Can take repeat argument or minimum length/width of precursor slab as an input Args: molecule (Molecule): molecule corresponding to adsorbate repeat (3-tuple or list): repeat argument for supercell generation min_lw (float): minimum length and width of the slab, only used if repeat is None reorient (bool): flag on whether or not to reorient adsorbate along the miller index find_args (dict): dictionary of arguments to be passed to the call to self.find_adsorption_sites, e.g. {"distance":2.0}

Response:
def generate_adsorption_structures(self, molecule, repeat=None, min_lw=5.0,
                                       reorient=True, find_args={}):
        """
        Function that generates all adsorption structures for a given
        molecular adsorbate.  Can take repeat argument or minimum
        length/width of precursor slab as an input

        Args:
            molecule (Molecule): molecule corresponding to adsorbate
            repeat (3-tuple or list): repeat argument for supercell generation
            min_lw (float): minimum length and width of the slab, only used
                if repeat is None
            reorient (bool): flag on whether or not to reorient adsorbate
                along the miller index
            find_args (dict): dictionary of arguments to be passed to the
                call to self.find_adsorption_sites, e.g. {"distance":2.0}
        """
        if repeat is None:
            xrep = np.ceil(min_lw / np.linalg.norm(self.slab.lattice.matrix[0]))
            yrep = np.ceil(min_lw / np.linalg.norm(self.slab.lattice.matrix[1]))
            repeat = [xrep, yrep, 1]
        structs = []

        for coords in self.find_adsorption_sites(**find_args)['all']:
            structs.append(self.add_adsorbate(
                molecule, coords, repeat=repeat, reorient=reorient))
        return structs


Instruction:
Can you generate a brief explanation for the following Python 3 code
def adsorb_both_surfaces(self, molecule, repeat=None, min_lw=5.0,
                             reorient=True, find_args={}):
        """
        Function that generates all adsorption structures for a given
        molecular adsorbate on both surfaces of a slab. This is useful
        for calculating surface energy where both surfaces need to be
        equivalent or if we want to calculate nonpolar systems.

        Args:
            molecule (Molecule): molecule corresponding to adsorbate
            repeat (3-tuple or list): repeat argument for supercell generation
            min_lw (float): minimum length and width of the slab, only used
                if repeat is None
            reorient (bool): flag on whether or not to reorient adsorbate
                along the miller index
            find_args (dict): dictionary of arguments to be passed to the
                call to self.find_adsorption_sites, e.g. {"distance":2.0}
        """

        # Get the adsorbed surfaces first
        adslabs = self.generate_adsorption_structures(molecule, repeat=repeat,
                                                      min_lw=min_lw,
                                                      reorient=reorient,
                                                      find_args=find_args)

        new_adslabs = []
        for adslab in adslabs:

            # Find the adsorbate sites and indices in each slab
            symmetric, adsorbates, indices = False, [], []
            for i, site in enumerate(adslab.sites):
                if site.surface_properties == "adsorbate":
                    adsorbates.append(site)
                    indices.append(i)

            # Start with the clean slab
            adslab.remove_sites(indices)
            slab = adslab.copy()

            # For each site, we add it back to the slab along with a
            # symmetrically equivalent position on the other side of
            # the slab using symmetry operations
            for adsorbate in adsorbates:
                p2 = adslab.get_symmetric_site(adsorbate.frac_coords)
                slab.append(adsorbate.specie, p2,
                            properties={"surface_properties": "adsorbate"})
                slab.append(adsorbate.specie, adsorbate.frac_coords,
                            properties={"surface_properties": "adsorbate"})
            new_adslabs.append(slab)

        return new_adslabs

Response: This function generates all adsorption structures for a given molecular adsorbate on both surfaces of a slab.


Instruction:
Can you create a Python 3 function that
functions that performs substitution-type doping on the surface and returns all possible configurations where one dopant is substituted per surface. Can substitute one surface or both. Args: atom (str): atom corresponding to substitutional dopant sub_both_sides (bool): If true, substitute an equivalent site on the other surface target_species (list): List of specific species to substitute range_tol (float): Find viable substitution sites at a specific distance from the surface +- this tolerance dist_from_surf (float): Distance from the surface to find viable substitution sites, defaults to 0 to substitute at the surface

Response:
def generate_substitution_structures(self, atom, target_species=[],
                                         sub_both_sides=False, range_tol=1e-2,
                                         dist_from_surf=0):
        """
        Function that performs substitution-type doping on the surface and
            returns all possible configurations where one dopant is substituted
            per surface. Can substitute one surface or both.

        Args:
            atom (str): atom corresponding to substitutional dopant
            sub_both_sides (bool): If true, substitute an equivalent
                site on the other surface
            target_species (list): List of specific species to substitute
            range_tol (float): Find viable substitution sites at a specific
                distance from the surface +- this tolerance
            dist_from_surf (float): Distance from the surface to find viable
                substitution sites, defaults to 0 to substitute at the surface
        """

        # Get symmetrized structure in case we want to substitue both sides
        sym_slab = SpacegroupAnalyzer(self.slab).get_symmetrized_structure()

        # Define a function for substituting a site
        def substitute(site, i):
            slab = self.slab.copy()
            props = self.slab.site_properties
            if sub_both_sides:
                # Find an equivalent site on the other surface
                eq_indices = [indices for indices in
                              sym_slab.equivalent_indices if i in indices][0]
                for ii in eq_indices:
                    if "%.6f" % (sym_slab[ii].frac_coords[2]) != \
                                    "%.6f" % (site.frac_coords[2]):
                        props["surface_properties"][ii] = "substitute"
                        slab.replace(ii, atom)
                        break

            props["surface_properties"][i] = "substitute"
            slab.replace(i, atom)
            slab.add_site_property("surface_properties",
                                   props["surface_properties"])
            return slab

        # Get all possible substitution sites
        substituted_slabs = []
        # Sort sites so that we can define a range relative to the position of the
        # surface atoms, i.e. search for sites above (below) the bottom (top) surface
        sorted_sites = sorted(sym_slab, key=lambda site: site.frac_coords[2])
        if sorted_sites[0].surface_properties == "surface":
            d = sorted_sites[0].frac_coords[2] + dist_from_surf
        else:
            d = sorted_sites[-1].frac_coords[2] - dist_from_surf

        for i, site in enumerate(sym_slab):
            if d - range_tol < site.frac_coords[2] < d + range_tol:
                if target_species and site.species_string in target_species:
                    substituted_slabs.append(substitute(site, i))
                elif not target_species:
                    substituted_slabs.append(substitute(site, i))

        matcher = StructureMatcher()
        return [s[0] for s in matcher.group_structures(substituted_slabs)]


Instruction:
How would you implement a function in Python 3 that
reads the exciting input from a string containing XML data.

Response:
def from_string(data):
        """
        Reads the exciting input from a string
        """

        root=ET.fromstring(data)
        speciesnode=root.find('structure').iter('species')
        elements = []
        positions = []
        vectors=[]
        lockxyz=[]
        # get title
        title_in=str(root.find('title').text)
        # Read elements and coordinates
        for nodes in speciesnode:
            symbol = nodes.get('speciesfile').split('.')[0]
            if len(symbol.split('_'))==2:
              symbol=symbol.split('_')[0]
            if Element.is_valid_symbol(symbol):
                # Try to recognize the element symbol
                element = symbol
            else:
                raise NLValueError("Unknown element!")
            natoms = nodes.getiterator('atom')
            for atom in natoms:
                x, y, z = atom.get('coord').split()
                positions.append([float(x), float(y), float(z)])
                elements.append(element)
                # Obtain lockxyz for each atom
                if atom.get('lockxyz') is not None:
                    lxy=[]
                    for l in atom.get('lockxyz').split():
                        if l=='True' or l=='true':
                            lxyz.append(True)
                        else:
                            lxyz.append(False)
                    lockxyz.append(lxyz)
                else:
                    lockxyz.append([False, False, False])
        #check the atomic positions type
        if 'cartesian' in root.find('structure').attrib.keys():
          if root.find('structure').attrib['cartesian']:
            cartesian=True
            for i in range(len(positions)):
                for j in range(3):
                    positions[i][j]=positions[i][j]*ExcitingInput.bohr2ang
            print(positions)
        else:
          cartesian=False
        # get the scale attribute
        scale_in=root.find('structure').find('crystal').get('scale')
        if scale_in:
            scale=float(scale_in)*ExcitingInput.bohr2ang
        else:
            scale=ExcitingInput.bohr2ang
       # get the stretch attribute
        stretch_in=root.find('structure').find('crystal').get('stretch')
        if stretch_in:
          stretch=np.array([float(a) for a in stretch_in])
        else:
          stretch=np.array([1.0,1.0,1.0])
        # get basis vectors and scale them accordingly
        basisnode=root.find('structure').find('crystal').iter('basevect')
        for vect in basisnode:
          x, y, z=vect.text.split()
          vectors.append([float(x)*stretch[0]*scale,
                          float(y)*stretch[1]*scale,
                          float(z)*stretch[2]*scale])
        # create lattice and structure object
        lattice_in=Lattice(vectors)
        structure_in=Structure(lattice_in,elements,positions,coords_are_cartesian=cartesian)

        return ExcitingInput(structure_in, title_in, lockxyz)


Instruction:
How would you explain what the following Python 3 function does
def types_of_specie(self):
        if not self.is_ordered:
            raise TypeError("""\
types_of_species cannot be used with disordered structures and partial occupancies.
Use OrderDisorderedStructureTransformation or EnumerateStructureTransformation
to build an appropriate supercell from partial occupancies.""")

        # Cannot use set since we want a deterministic algorithm.
        types = []
        for site in self:
            if site.specie not in types:
                types.append(site.specie)
        return types

Response: Returns a list of types of species. Only works for ordered structures and disordered structures will raise TypeError.


Instruction:
Make a summary of the following Python 3 code
def group_by_types(self):
        for t in self.types_of_specie:
            for site in self:
                if site.specie == t:
                    yield site

Response: Iterate over species grouped by type


Instruction:
Create a Python 3 function to
return a tuple with the sequential indices of the sites that contain an element with the given chemical symbol.

Response:
def indices_from_symbol(self, symbol: str) -> tuple:
        """
        Returns a tuple with the sequential indices of the sites
        that contain an element with the given chemical symbol.
        """
        return tuple((i for i, specie in enumerate(self.species)
                      if specie.symbol == symbol))


Instruction:
Explain what the following Python 3 code does
def site_properties(self):
        props = {}
        prop_keys = set()
        for site in self:
            prop_keys.update(site.properties.keys())

        for k in prop_keys:
            props[k] = [site.properties.get(k, None) for site in self]
        return props

Response: Returns the site properties as a dict of sequences. E. g..


Instruction:
Explain what the following Python 3 code does
def composition(self):
        elmap = collections.defaultdict(float)
        for site in self:
            for species, occu in site.species.items():
                elmap[species] += occu
        return Composition(elmap)

Response: Returns the composition of the species and occu of all sites in the site.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def charge(self):
        charge = 0
        for site in self:
            for specie, amt in site.species.items():
                charge += getattr(specie, "oxi_state", 0) * amt
        return charge

Response: Returns the net charge of the structure based on oxidation states.


Instruction:
How would you explain what the following Python 3 function does
def get_angle(self, i: int, j: int, k: int) -> float:
        v1 = self[i].coords - self[j].coords
        v2 = self[k].coords - self[j].coords
        return get_angle(v1, v2, units="degrees")

Response: Returns angle in degrees of the third site of the set of two - site tables.