Instruction:
Can you generate a brief explanation for the following Python 3 code
def _create(self, monomer, mon_vector):
        while self.length != (self.n_units-1):
            if self.linear_chain:
                move_direction = np.array(mon_vector) / np.linalg.norm(mon_vector)
            else:
                move_direction = self._next_move_direction()
            self._add_monomer(monomer.copy(), mon_vector, move_direction)

Response: Create the polymer from the monomer.


Instruction:
Create a Python 3 function to
pick a move at random from the list of moves

Response:
def _next_move_direction(self):
        """
        pick a move at random from the list of moves
        """
        nmoves = len(self.moves)
        move = np.random.randint(1, nmoves+1)
        while self.prev_move == (move + 3) % nmoves:
            move = np.random.randint(1, nmoves+1)
        self.prev_move = move
        return np.array(self.moves[move])


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _align_monomer(self, monomer, mon_vector, move_direction):
        axis = np.cross(mon_vector, move_direction)
        origin = monomer[self.start].coords
        angle = get_angle(mon_vector, move_direction)
        op = SymmOp.from_origin_axis_angle(origin, axis, angle)
        monomer.apply_operation(op)

Response: Aligns the monomer with the given mon_vector along the given move direction.


Instruction:
Can you generate the documentation for the following Python 3 function
def _add_monomer(self, monomer, mon_vector, move_direction):
        translate_by = self.molecule.cart_coords[self.end] + \
                       self.link_distance * move_direction
        monomer.translate_sites(range(len(monomer)), translate_by)
        if not self.linear_chain:
            self._align_monomer(monomer, mon_vector, move_direction)
        # add monomer if there are no crossings
        does_cross = False
        for i, site in enumerate(monomer):
            try:
                self.molecule.append(site.specie, site.coords,
                                     properties=site.properties)
            except:
                does_cross = True
                polymer_length = len(self.molecule)
                self.molecule.remove_sites(
                    range(polymer_length - i, polymer_length))
                break
        if not does_cross:
            self.length += 1
            self.end += len(self.monomer)

Response: extend the polymer molecule by adding a monomer along mon_vector direction


Instruction:
Here you have a function in Python 3, explain what it does
def _format_param_val(self, param_val):
        if isinstance(param_val, list):
            return ' '.join(str(x) for x in param_val)
        else:
            return str(param_val)

Response:
Internal method to format values in the packmol parameter dictionaries
erset.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _set_box(self):
        net_volume = 0.0
        for idx, mol in enumerate(self.mols):
            length = max([np.max(mol.cart_coords[:, i])-np.min(mol.cart_coords[:, i])
                           for i in range(3)]) + 2.0
            net_volume += (length**3.0) * float(self.param_list[idx]['number'])
        length = net_volume**(1.0/3.0)
        for idx, mol in enumerate(self.mols):
            self.param_list[idx]['inside box'] = '0.0 0.0 0.0 {} {} {}'.format(
                length, length, length)

Response: Set the box size for the molecular assembly.


Instruction:
Can you tell what is the following Python 3 function doing
def _write_input(self, input_dir="."):
        with open(os.path.join(input_dir, self.input_file), 'wt', encoding="utf-8") as inp:
            for k, v in self.control_params.items():
                inp.write('{} {}\n'.format(k, self._format_param_val(v)))
            # write the structures of the constituent molecules to file and set
            # the molecule id and the corresponding filename in the packmol
            # input file.
            for idx, mol in enumerate(self.mols):
                filename = os.path.join(
                    input_dir, '{}.{}'.format(
                        idx, self.control_params["filetype"])).encode("ascii")
                # pdb
                if self.control_params["filetype"] == "pdb":
                    self.write_pdb(mol, filename, num=idx+1)
                # all other filetypes
                else:
                    a = BabelMolAdaptor(mol)
                    pm = pb.Molecule(a.openbabel_mol)
                    pm.write(self.control_params["filetype"], filename=filename,
                             overwrite=True)

                inp.write("\n")
                inp.write(
                    "structure {}.{}\n".format(
                        os.path.join(input_dir, str(idx)),
                        self.control_params["filetype"]))
                for k, v in self.param_list[idx].items():
                    inp.write('  {} {}\n'.format(k, self._format_param_val(v)))
                inp.write('end structure\n')

Response: Write the packmol input file to the input directory.


Instruction:
Write a Python 3 function that can
write the input file to the scratch directory run packmol and return the packed molecule.

Response:
def run(self, copy_to_current_on_exit=False, site_property=None):
        """
        Write the input file to the scratch directory, run packmol and return
        the packed molecule.

        Args:
            copy_to_current_on_exit (bool): Whether or not to copy the packmol
                input/output files from the scratch directory to the current
                directory.
            site_property (str): if set then the specified site property
                for the the final packed molecule will be restored.

        Returns:
                Molecule object
        """
        scratch = tempfile.gettempdir()
        with ScratchDir(scratch, copy_to_current_on_exit=copy_to_current_on_exit) as scratch_dir:
            self._write_input(input_dir=scratch_dir)
            packmol_input = open(os.path.join(scratch_dir, self.input_file), 'r')
            p = Popen(self.packmol_bin, stdin=packmol_input, stdout=PIPE, stderr=PIPE)
            (stdout, stderr) = p.communicate()
            output_file = os.path.join(scratch_dir, self.control_params["output"])
            if os.path.isfile(output_file):
                packed_mol = BabelMolAdaptor.from_file(output_file,
                                                       self.control_params["filetype"])
                packed_mol = packed_mol.pymatgen_mol
                print("packed molecule written to {}".format(
                    self.control_params["output"]))
                if site_property:
                    packed_mol = self.restore_site_properties(site_property=site_property, filename=output_file)
                return packed_mol
            else:
                print("Packmol execution failed")
                print(stdout, stderr)
                return None


Instruction:
Can you implement a function in Python 3 that
dumps the molecule into pdb file with custom residue name and number.

Response:
def write_pdb(self, mol, filename, name=None, num=None):
        """
        dump the molecule into pdb file with custom residue name and number.
        """

        # ugly hack to get around the openbabel issues with inconsistent
        # residue labelling.
        scratch = tempfile.gettempdir()
        with ScratchDir(scratch, copy_to_current_on_exit=False) as _:
            mol.to(fmt="pdb", filename="tmp.pdb")
            bma = BabelMolAdaptor.from_file("tmp.pdb", "pdb")

        num = num or 1
        name = name or "ml{}".format(num)

        # bma = BabelMolAdaptor(mol)
        pbm = pb.Molecule(bma._obmol)
        for i, x in enumerate(pbm.residues):
            x.OBResidue.SetName(name)
            x.OBResidue.SetNum(num)

        pbm.write(format="pdb", filename=filename, overwrite=True)


Instruction:
Write a Python 3 function for
mapping each residue to the corresponding molecule.

Response:
def _set_residue_map(self):
        """
        map each residue to the corresponding molecule.
        """
        self.map_residue_to_mol = {}
        lookup = {}
        for idx, mol in enumerate(self.mols):
            if not mol.formula in lookup:
                mol.translate_sites(indices=range(len(mol)),
                                    vector=-mol.center_of_mass)
                lookup[mol.formula] = mol.copy()
            self.map_residue_to_mol["ml{}".format(idx + 1)] = lookup[mol.formula]


Instruction:
Can you create a Python 3 function that
converts list of openbabel atoms to Molecule.

Response:
def convert_obatoms_to_molecule(self, atoms, residue_name=None, site_property="ff_map"):
        """
        Convert list of openbabel atoms to MOlecule.

        Args:
            atoms ([OBAtom]): list of OBAtom objects
            residue_name (str): the key in self.map_residue_to_mol. Usec to
                restore the site properties in the final packed molecule.
            site_property (str): the site property to be restored.

        Returns:
            Molecule object
        """

        restore_site_props = True if residue_name is not None else False

        if restore_site_props and not hasattr(self, "map_residue_to_mol"):
            self._set_residue_map()

        coords = []
        zs = []
        for atm in atoms:
            coords.append(list(atm.coords))
            zs.append(atm.atomicnum)

        mol = Molecule(zs, coords)

        if restore_site_props:

            props = []

            ref = self.map_residue_to_mol[residue_name].copy()

            # sanity check
            assert len(mol) == len(ref)
            assert ref.formula == mol.formula

            # the packed molecules have the atoms in the same order..sigh!
            for i, site in enumerate(mol):
                assert site.specie.symbol == ref[i].specie.symbol
                props.append(getattr(ref[i], site_property))

            mol.add_site_property(site_property, props)

        return mol


Instruction:
Can you generate the documentation for the following Python 3 function
def restore_site_properties(self, site_property="ff_map", filename=None):

        # only for pdb
        if not self.control_params["filetype"] == "pdb":
            raise ValueError()

        filename = filename or self.control_params["output"]
        bma = BabelMolAdaptor.from_file(filename, "pdb")
        pbm = pb.Molecule(bma._obmol)

        assert len(pbm.residues) == sum([x["number"]
                                         for x in self.param_list])

        packed_mol = self.convert_obatoms_to_molecule(
            pbm.residues[0].atoms, residue_name=pbm.residues[0].name,
            site_property=site_property)

        for resid in pbm.residues[1:]:
            mol = self.convert_obatoms_to_molecule(
                resid.atoms, residue_name=resid.name,
                site_property=site_property)
            for site in mol:
                packed_mol.append(site.species, site.coords,
                                  properties=site.properties)

        return packed_mol

Response: Restore the site properties for the final packed molecule.


Instruction:
How would you explain what the following Python 3 function does
def run(self):
        lammps_cmd = self.lammps_bin + ['-in', self.input_filename]
        print("Running: {}".format(" ".join(lammps_cmd)))
        p = Popen(lammps_cmd, stdout=PIPE, stderr=PIPE)
        (stdout, stderr) = p.communicate()
        return stdout, stderr

Response: Write the input files and run LAMMPS.


Instruction:
Make a summary of the following Python 3 code
def get_el_sp(obj):
    if isinstance(obj, (Element, Specie, DummySpecie)):
        return obj

    if isinstance(obj, (list, tuple)):
        return [get_el_sp(o) for o in obj]

    try:
        c = float(obj)
        i = int(c)
        i = i if i == c else None
    except (ValueError, TypeError):
        i = None

    if i is not None:
        return Element.from_Z(i)

    try:
        return Specie.from_string(obj)
    except (ValueError, KeyError):
        try:
            return Element(obj)
        except (ValueError, KeyError):
            try:
                return DummySpecie.from_string(obj)
            except:
                raise ValueError("Can't parse Element or String from type"
                                 " %s: %s." % (type(obj), obj))

Response: Utility method to get an Element or Specie from an arbitrary object.


Instruction:
How would you implement a function in Python 3 that
averages ionic radius for element.

Response:
def average_ionic_radius(self):
        """
        Average ionic radius for element (with units). The average is taken
        over all oxidation states of the element for which data is present.
        """
        if "Ionic radii" in self._data:
            radii = self._data["Ionic radii"]
            return sum(radii.values()) / len(radii)
        else:
            return 0


Instruction:
Can you generate a brief explanation for the following Python 3 code
def average_cationic_radius(self):
        if "Ionic radii" in self._data:
            radii = [v for k, v in self._data["Ionic radii"].items()
                     if int(k) > 0]
            if radii:
                return sum(radii) / len(radii)
        return 0

Response: Average cationic radius for the element.


Instruction:
Write a Python 3 function for
returning the ionic radii of the element as a dict of oxidation state ionic radii.

Response:
def ionic_radii(self):
        """
        All ionic radii of the element as a dict of
        {oxidation state: ionic radii}. Radii are given in ang.
        """
        if "Ionic radii" in self._data:
            return {int(k): v for k, v in self._data["Ionic radii"].items()}
        else:
            return {}


Instruction:
Write a Python 3 script to
full electronic structure as tuple.

Response:
def full_electronic_structure(self):
        """
        Full electronic structure as tuple.
        E.g., The electronic structure for Fe is represented as:
        [(1, "s", 2), (2, "s", 2), (2, "p", 6), (3, "s", 2), (3, "p", 6),
        (3, "d", 6), (4, "s", 2)]
        """
        estr = self._data["Electronic structure"]

        def parse_orbital(orbstr):
            m = re.match(r"(\d+)([spdfg]+)<sup>(\d+)</sup>", orbstr)
            if m:
                return int(m.group(1)), m.group(2), int(m.group(3))
            return orbstr

        data = [parse_orbital(s) for s in estr.split(".")]
        if data[0][0] == "[":
            sym = data[0].replace("[", "").replace("]", "")
            data = Element(sym).full_electronic_structure + data[1:]
        return data


Instruction:
Make a summary of the following Python 3 code
def valence(self):
        # the number of valence of noble gas is 0
        if self.group == 18:
            return (np.nan, 0)

        L_symbols = 'SPDFGHIKLMNOQRTUVWXYZ'
        valence = []
        full_electron_config = self.full_electronic_structure
        for _, l_symbol, ne in full_electron_config[::-1]:
            l = L_symbols.lower().index(l_symbol)
            if ne < (2 * l + 1) * 2:
                valence.append((l, ne))
        if len(valence) > 1:
            raise ValueError("Ambiguous valence")

        return valence[0]

Response: Get the valence of the noble gas from the full electronic structure.


Instruction:
Explain what the following Python 3 code does
def term_symbols(self):
        L_symbols = 'SPDFGHIKLMNOQRTUVWXYZ'

        L, v_e = self.valence

        # for one electron in subshell L
        ml = list(range(-L, L + 1))
        ms = [1 / 2, -1 / 2]
        # all possible configurations of ml,ms for one e in subshell L
        ml_ms = list(product(ml, ms))

        # Number of possible configurations for r electrons in subshell L.
        n = (2 * L + 1) * 2
        # the combination of n_e electrons configurations
        # C^{n}_{n_e}
        e_config_combs = list(combinations(range(n), v_e))

        # Total ML = sum(ml1, ml2), Total MS = sum(ms1, ms2)
        TL = [sum([ml_ms[comb[e]][0] for e in range(v_e)])
              for comb in e_config_combs]
        TS = [sum([ml_ms[comb[e]][1] for e in range(v_e)])
              for comb in e_config_combs]
        comb_counter = Counter([r for r in zip(TL, TS)])

        term_symbols = []
        while sum(comb_counter.values()) > 0:
            # Start from the lowest freq combination,
            # which corresponds to largest abs(L) and smallest abs(S)
            L, S = min(comb_counter)

            J = list(np.arange(abs(L - S), abs(L) + abs(S) + 1))
            term_symbols.append([str(int(2 * (abs(S)) + 1))
                                 + L_symbols[abs(L)]
                                 + str(j) for j in J])
            # Without J
            # term_symbols.append(str(int(2 * (abs(S)) + 1)) \
            #                     + L_symbols[abs(L)])

            # Delete all configurations included in this term
            for ML in range(-L, L - 1, -1):
                for MS in np.arange(S, -S + 1, 1):
                    if (ML, MS) in comb_counter:

                        comb_counter[(ML, MS)] -= 1
                        if comb_counter[(ML, MS)] == 0:
                            del comb_counter[(ML, MS)]
        return term_symbols

Response: Returns a list of all possible Russell - Saunders term symbols of the current locale.


Instruction:
Given the following Python 3 function, write the documentation
def ground_state_term_symbol(self):
        L_symbols = 'SPDFGHIKLMNOQRTUVWXYZ'

        term_symbols = self.term_symbols
        term_symbol_flat = {term: {"multiplicity": int(term[0]),
                                   "L": L_symbols.index(term[1]),
                                   "J": float(term[2:])}
                            for term in sum(term_symbols, [])}

        multi = [int(item['multiplicity'])
                 for terms, item in term_symbol_flat.items()]
        max_multi_terms = {symbol: item
                           for symbol, item in term_symbol_flat.items()
                           if item['multiplicity'] == max(multi)}

        Ls = [item['L'] for terms, item in max_multi_terms.items()]
        max_L_terms = {symbol: item
                       for symbol, item in term_symbol_flat.items()
                       if item['L'] == max(Ls)}

        J_sorted_terms = sorted(max_L_terms.items(),
                                key=lambda k: k[1]['J'])
        L, v_e = self.valence
        if v_e <= (2 * L + 1):
            return J_sorted_terms[0][0]
        else:
            return J_sorted_terms[-1][0]

Response: Returns the ground state term symbol that is selected based on Hund s Rule s TermSymbol.


Instruction:
Here you have a function in Python 3, explain what it does
def from_Z(z: int):
        for sym, data in _pt_data.items():
            if data["Atomic no"] == z:
                return Element(sym)
        raise ValueError("No element with this atomic number %s" % z)

Response: Get an element from an atomic number.


Instruction:
Write a Python 3 script for
returning an element from a row and group number.

Response:
def from_row_and_group(row: int, group: int):
        """
        Returns an element from a row and group number.

        Args:
            row (int): Row number
            group (int): Group number

        .. note::
            The 18 group number system is used, i.e., Noble gases are group 18.
        """
        for sym in _pt_data.keys():
            el = Element(sym)
            if el.row == row and el.group == group:
                return el
        raise ValueError("No element with this row and group!")


Instruction:
Explain what the following Python 3 code does
def row(self):
        z = self.Z
        total = 0
        if 57 <= z <= 71:
            return 8
        elif 89 <= z <= 103:
            return 9

        for i in range(len(_pt_row_sizes)):
            total += _pt_row_sizes[i]
            if total >= z:
                return i + 1
        return 8

Response: Returns the periodic table row of the element.


Instruction:
Here you have a function in Python 3, explain what it does
def group(self):
        z = self.Z
        if z == 1:
            return 1
        if z == 2:
            return 18
        if 3 <= z <= 18:
            if (z - 2) % 8 == 0:
                return 18
            elif (z - 2) % 8 <= 2:
                return (z - 2) % 8
            else:
                return 10 + (z - 2) % 8

        if 19 <= z <= 54:
            if (z - 18) % 18 == 0:
                return 18
            else:
                return (z - 18) % 18

        if (z - 54) % 32 == 0:
            return 18
        elif (z - 54) % 32 >= 18:
            return (z - 54) % 32 - 14
        else:
            return (z - 54) % 32

Response: Returns the periodic table group of the element.


Instruction:
Implement a Python 3 function for
returning the block character s p d f

Response:
def block(self):
        """
        Return the block character "s,p,d,f"
        """
        if (self.is_actinoid or self.is_lanthanoid) and self.Z not in [71, 103]:
            return "f"
        elif self.is_actinoid or self.is_lanthanoid:
            return "d"
        elif self.group in [1, 2]:
            return "s"
        elif self.group in range(13, 19):
            return "p"
        elif self.group in range(3, 13):
            return "d"
        raise ValueError("unable to determine block")


Instruction:
Here you have a function in Python 3, explain what it does
def is_transition_metal(self):
        ns = list(range(21, 31))
        ns.extend(list(range(39, 49)))
        ns.append(57)
        ns.extend(list(range(72, 81)))
        ns.append(89)
        ns.extend(list(range(104, 113)))
        return self.Z in ns

Response: True if the element is a transition metal.


Instruction:
Can you generate the documentation for the following Python 3 function
def nmr_quadrupole_moment(self):
        return {k: FloatWithUnit(v, "mbarn")
                for k, v in self.data.get("NMR Quadrupole Moment", {}).items()}

Response:
Get a dictionary of nuclear electric quadrupole moment in units of
        e*millibarns for various isotopes


Instruction:
Write a Python 3 function for
returning a dict representation of the object.

Response:
def as_dict(self):
        """
        Makes Element obey the general json interface used in pymatgen for
        easier serialization.
        """
        return {"@module": self.__class__.__module__,
                "@class": self.__class__.__name__,
                "element": self.symbol}


Instruction:
Make a summary of the following Python 3 code
def ionic_radius(self):

        if self._oxi_state in self.ionic_radii:
            return self.ionic_radii[self._oxi_state]
        d = self._el.data
        oxstr = str(int(self._oxi_state))
        if oxstr in d.get("Ionic radii hs", {}):
            warnings.warn("No default ionic radius for %s. Using hs data." %
                          self)
            return d["Ionic radii hs"][oxstr]
        elif oxstr in d.get("Ionic radii ls", {}):
            warnings.warn("No default ionic radius for %s. Using ls data." %
                          self)
            return d["Ionic radii ls"][oxstr]
        warnings.warn("No ionic radius for {}!".format(self))
        return None

Response: Returns the ionic radius of the current specie. Returns None if data is not present.


Instruction:
Explain what the following Python 3 code does
def from_string(species_string: str):
        m = re.search(r"([A-Z][a-z]*)([0-9.]*)([+\-])(.*)", species_string)
        if m:
            sym = m.group(1)
            oxi = 1 if m.group(2) == "" else float(m.group(2))
            oxi = -oxi if m.group(3) == "-" else oxi
            properties = None
            if m.group(4):
                toks = m.group(4).replace(",", "").split("=")
                properties = {toks[0]: float(toks[1])}
            return Specie(sym, oxi, properties)
        else:
            raise ValueError("Invalid Species String")

Response: Returns a Specie object from a string representation.


Instruction:
Can you create a Python 3 function that
gets the nuclear electric quadrupole moment in units of millibarns e*millibarns

Response:
def get_nmr_quadrupole_moment(self, isotope=None):
        """
        Gets the nuclear electric quadrupole moment in units of
        e*millibarns

        Args:
            isotope (str): the isotope to get the quadrupole moment for
                default is None, which gets the lowest mass isotope
        """

        quad_mom = self._el.nmr_quadrupole_moment

        if len(quad_mom) == 0:
            return 0.0

        if isotope is None:
            isotopes = list(quad_mom.keys())
            isotopes.sort(key=lambda x: int(x.split("-")[1]), reverse=False)
            return quad_mom.get(isotopes[0], 0.0)
        else:
            if isotope not in quad_mom:
                raise ValueError("No quadrupole moment for isotope {}".format(
                    isotope))
            return quad_mom.get(isotope, 0.0)


Instruction:
How would you explain what the following Python 3 function does
def get_shannon_radius(self, cn: str, spin: str = "",
                           radius_type: str = "ionic"):
        """
        Get the local environment specific ionic radius for species.

        Args:
            cn (str): Coordination using roman letters. Supported values are
                I-IX, as well as IIIPY, IVPY and IVSQ.
            spin (str): Some species have different radii for different
                spins. You can get specific values using "High Spin" or
                "Low Spin". Leave it as "" if not available. If only one spin
                data is available, it is returned and this spin parameter is
                ignored.
            radius_type (str): Either "crystal" or "ionic" (default).

        Returns:
            Shannon radius for specie in the specified environment.
        """
        radii = self._el.data["Shannon radii"]
        # if cn == 1:
        #     cn_str = "I"
        # elif cn == 2:
        #     cn_str = "II"
        # elif cn == 3:
        #     cn_str = "III"
        # elif cn == 4:
        #     cn_str = "IV"
        # elif cn == 5:
        #     cn_str = "V"
        # elif cn == 6:
        #     cn_str = "VI"
        # elif cn == 7:
        #     cn_str = "VII"
        # elif cn == 8:
        #     cn_str = "VIII"
        # elif cn == 9:
        #     cn_str = "IX"
        # else:
        #     raise ValueError("Invalid coordination number")

        if len(radii[str(int(self._oxi_state))][cn]) == 1:
            k, data = list(radii[str(int(self._oxi_state))][cn].items())[0]
            if k != spin:
                warnings.warn(
                    "Specified spin state of %s not consistent with database "
                    "spin of %s. Only one spin data available, and "
                    "that value is returned." % (spin, k)
                )
        else:
            data = radii[str(int(self._oxi_state))][cn][spin]
        return data["%s_radius" % radius_type]

Response: Returns the ionic radius for a specific environment.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_crystal_field_spin(self, coordination: str = "oct",
                               spin_config: str = "high"):
        """
        Calculate the crystal field spin based on coordination and spin
        configuration. Only works for transition metal species.

        Args:
            coordination (str): Only oct and tet are supported at the moment.
            spin_config (str): Supported keywords are "high" or "low".

        Returns:
            Crystal field spin in Bohr magneton.

        Raises:
            AttributeError if species is not a valid transition metal or has
            an invalid oxidation state.
            ValueError if invalid coordination or spin_config.
        """
        if coordination not in ("oct", "tet") or \
                spin_config not in ("high", "low"):
            raise ValueError("Invalid coordination or spin config.")
        elec = self.full_electronic_structure
        if len(elec) < 4 or elec[-1][1] != "s" or elec[-2][1] != "d":
            raise AttributeError(
                "Invalid element {} for crystal field calculation.".format(
                    self.symbol))
        nelectrons = elec[-1][2] + elec[-2][2] - self.oxi_state
        if nelectrons < 0 or nelectrons > 10:
            raise AttributeError(
                "Invalid oxidation state {} for element {}"
                .format(self.oxi_state, self.symbol))
        if spin_config == "high":
            return nelectrons if nelectrons <= 5 else 10 - nelectrons
        elif spin_config == "low":
            if coordination == "oct":
                if nelectrons <= 3:
                    return nelectrons
                elif nelectrons <= 6:
                    return 6 - nelectrons
                elif nelectrons <= 8:
                    return nelectrons - 6
                else:
                    return 10 - nelectrons
            elif coordination == "tet":
                if nelectrons <= 2:
                    return nelectrons
                elif nelectrons <= 4:
                    return 4 - nelectrons
                elif nelectrons <= 7:
                    return nelectrons - 4
                else:
                    return 10 - nelectrons

Response: Calculates the crystal field spin based on the coordination and spin_config.


Instruction:
Write a Python 3 script to
return a Dummy object from a string representation.

Response:
def from_string(species_string: str):
        """
        Returns a Dummy from a string representation.

        Args:
            species_string (str): A string representation of a dummy
                species, e.g., "X2+", "X3+".

        Returns:
            A DummySpecie object.

        Raises:
            ValueError if species_string cannot be intepreted.
        """
        m = re.search(r"([A-Z][a-z]*)([0-9.]*)([+\-]*)(.*)", species_string)
        if m:
            sym = m.group(1)
            if m.group(2) == "" and m.group(3) == "":
                oxi = 0
            else:
                oxi = 1 if m.group(2) == "" else float(m.group(2))
                oxi = -oxi if m.group(3) == "-" else oxi
            properties = None
            if m.group(4):
                toks = m.group(4).split("=")
                properties = {toks[0]: float(toks[1])}
            return DummySpecie(sym, oxi, properties)
        raise ValueError("Invalid DummySpecies String")


Instruction:
Write a Python 3 function that can
return a DummySpecie object that can be safely used by a given composition.

Response:
def safe_from_composition(cls, comp: "Composition",
                              oxidation_state: float = 0):
        """
        Returns a DummySpecie object that can be safely used
        with (i.e. not present in) a given composition
        """
        # We don't want to add a DummySpecie with the same
        # symbol as anything in the composition, even if the
        # oxidation state is different
        els = comp.element_composition.elements
        for c in 'abcdfghijklmnopqrstuvwxyz':
            if DummySpecie('X' + c) not in els:
                return DummySpecie('X' + c, oxidation_state)
        raise ValueError("All attempted DummySpecies already "
                         "present in {}".format(comp))


Instruction:
How would you code a function in Python 3 to
process a given defect entry and return a dict of all possible defect corrections and flag as delocalized

Response:
def process_entry(self, defect_entry):
        """
        Process a given Defect entry with qualifiers given from initialization of class.
        Order of processing is:
            1) perform all possible defect corrections with information given
            2) consider delocalization analyses based on qualifier metrics
            given initialization of class. If delocalized, flag entry as delocalized
            3) update corrections to defect entry and flag as del

        Corrections are applied based on:
            i) if free charges are more than free_chg_cutoff then will not apply charge correction,
                because it no longer is applicable
            ii) use charge correction set by preferred_cc
            iii) only use BandFilling correction if use_bandfilling is set to True
            iv) only use BandEdgeShift correction if use_bandedgeshift is set to True
        """
        self.perform_all_corrections(defect_entry)

        self.delocalization_analysis(defect_entry)

        # apply corrections based on delocalization analysis
        corrections = {}
        skip_charge_corrections = False
        if "num_hole_vbm" in defect_entry.parameters.keys():
            if (self.free_chg_cutoff < defect_entry.parameters["num_hole_vbm"]) or (
                self.free_chg_cutoff < defect_entry.parameters["num_elec_cbm"]):
                print('Will not use charge correction because too many free charges')
                # TODO: should the potential alignment correction still be used in this scenario?
                # TODO: with too much charge delocalized should probably not use?
                skip_charge_corrections = True

        if skip_charge_corrections:
            corrections.update({'charge_correction': 0.})
        else:
            if ('freysoldt' in self.preferred_cc.lower()) and ('freysoldt_meta' in defect_entry.parameters.keys()):
                frey_meta = defect_entry.parameters['freysoldt_meta']
                frey_corr = frey_meta["freysoldt_electrostatic"] + frey_meta["freysoldt_potential_alignment_correction"]
                corrections.update({'charge_correction': frey_corr})
            elif ('kumagai_meta' in defect_entry.parameters.keys()):
                kumagai_meta = defect_entry.parameters['kumagai_meta']
                kumagai_corr = kumagai_meta["kumagai_electrostatic"] + \
                    kumagai_meta["kumagai_potential_alignment_correction"]
                corrections.update({'charge_correction': kumagai_corr})
            else:
                print('Could not use any charge correction because insufficient metadata was supplied.')

        if self.use_bandfilling:
            if "bandfilling_meta" in defect_entry.parameters.keys():
                bfc_corr = defect_entry.parameters["bandfilling_meta"]["bandfilling_correction"]
                corrections.update({'bandfilling_correction': bfc_corr})
            else:
                print('Could not use band filling correction because insufficient metadata was supplied.')
        else:
            corrections.update({'bandfilling_correction': 0.})

        if self.use_bandedgeshift:
            if "bandshift_meta" in defect_entry.parameters.keys():
                bandfill_meta = defect_entry.parameters["bandshift_meta"]
                bes_corr = bandfill_meta["vbm_shift_correction"] + bandfill_meta["hole_vbm_shift_correction"] + \
                    bandfill_meta["elec_cbm_shift_correction"]
                corrections.update({'bandedgeshifting_correction': bes_corr})

                # also want to update relevant data for phase diagram
                defect_entry.parameters.update({
                    'phasediagram_meta': {
                        'vbm': defect_entry.parameters['hybrid_vbm'],
                        'gap': defect_entry.parameters['hybrid_cbm'] - defect_entry.parameters['hybrid_vbm']
                    }
                })
            else:
                print("Could not use band edge shifting correction because insufficient metadata was supplied.")
                defect_entry.parameters.update({
                'phasediagram_meta': {
                    'vbm': defect_entry.parameters['vbm'],
                    'gap': defect_entry.parameters['cbm'] - defect_entry.parameters['vbm']
                    }
                })

        else:  # if not using bandedge shift -> still want to have vbm and gap ready for phase diagram
            corrections.update({'bandedgeshifting_correction': 0.})
            defect_entry.parameters.update({
                'phasediagram_meta': {
                    'vbm': defect_entry.parameters['vbm'],
                    'gap': defect_entry.parameters['cbm'] - defect_entry.parameters['vbm']
                }
            })

        defect_entry.corrections.update(corrections)

        return defect_entry


Instruction:
Can you tell what is the following Python 3 function doing
def delocalization_analysis(self, defect_entry):
        defect_entry.parameters.update({'is_compatible': True}) #this will be switched to False if delocalization is detected

        if 'freysoldt_meta' in defect_entry.parameters.keys():
            defect_entry = self.is_freysoldt_delocalized(defect_entry)
        else:
            print('Insufficient information provided for performing Freysoldt '
                  'correction delocalization analysis.\n'
                  'Cannot perform planar averaged electrostatic potential '
                  'compatibility analysis.')

        if 'kumagai_meta' in defect_entry.parameters.keys():
            defect_entry = self.is_kumagai_delocalized(defect_entry)
        else:
            print('Insufficient information provided for performing Kumagai '
                  'correction delocalization analysis.\n'
                  'Cannot perform atomic site averaged electrostatic '
                  'potential compatibility analysis.')

        if ('final_defect_structure' in defect_entry.parameters.keys()) and \
                ('initial_defect_structure' in defect_entry.parameters.keys()) and \
                ('sampling_radius' in defect_entry.parameters.keys()):
            defect_entry = self.is_final_relaxed_structure_delocalized(defect_entry)
        else:
            print('Insufficient information provided in defect_entry.parameters. '
                  'Cannot perform full structure site relaxation compatibility analysis.')

        return defect_entry

Response: Do delocalization analysis for a single defect entry.


Instruction:
Write a Python 3 script to
determine the distance of space between the slab and the last atom along c

Response:
def get_d(slab):
    """
    Determine the distance of space between
    each layer of atoms along c
    """
    sorted_sites = sorted(slab, key=lambda site: site.frac_coords[2])
    for i, site in enumerate(sorted_sites):
        if "%.6f" % (site.frac_coords[2]) == \
                        "%.6f" % (sorted_sites[i + 1].frac_coords[2]):
            continue
        else:
            d = abs(site.frac_coords[2] - \
                    sorted_sites[i + 1].frac_coords[2])
            break
    return slab.lattice.get_cartesian_coords([0, 0, d])[2]


Instruction:
Here you have a function in Python 3, explain what it does
def get_recp_symmetry_operation(structure, symprec=0.01):
    recp_lattice = structure.lattice.reciprocal_lattice_crystallographic
    # get symmetry operations from input conventional unit cell
    # Need to make sure recp lattice is big enough, otherwise symmetry
    # determination will fail. We set the overall volume to 1.
    recp_lattice = recp_lattice.scale(1)
    recp = Structure(recp_lattice, ["H"], [[0, 0, 0]])
    # Creates a function that uses the symmetry operations in the
    # structure to find Miller indices that might give repetitive slabs
    analyzer = SpacegroupAnalyzer(recp, symprec=symprec)
    recp_symmops = analyzer.get_symmetry_operations()

    return recp_symmops

Response: Returns a function that returns the symmetry operations of the reciprocal lattice and the Miller indices that might give repetitive slabs.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_symmetrically_distinct_miller_indices(structure, max_index):

    r = list(range(-max_index, max_index + 1))
    r.reverse()

    # First we get a list of all hkls for conventional (including equivalent)
    conv_hkl_list = [miller for miller in itertools.product(r, r, r) if any([i != 0 for i in miller])]

    sg = SpacegroupAnalyzer(structure)
    # Get distinct hkl planes from the rhombohedral setting if trigonal
    if sg.get_crystal_system() == "trigonal":
        transf = sg.get_conventional_to_primitive_transformation_matrix()
        miller_list = [hkl_transformation(transf, hkl) for hkl in conv_hkl_list]
        prim_structure = SpacegroupAnalyzer(structure).get_primitive_standard_structure()
        symm_ops = get_recp_symmetry_operation(prim_structure)
    else:
        miller_list = conv_hkl_list
        symm_ops = get_recp_symmetry_operation(structure)

    unique_millers, unique_millers_conv = [], []

    def is_already_analyzed(miller_index):
        for op in symm_ops:
            if in_coord_list(unique_millers, op.operate(miller_index)):
                return True
        return False

    for i, miller in enumerate(miller_list):
        d = abs(reduce(gcd, miller))
        miller = tuple([int(i / d) for i in miller])
        if not is_already_analyzed(miller):
            if sg.get_crystal_system() == "trigonal":
                # Now we find the distinct primitive hkls using
                # the primitive symmetry operations and their
                # corresponding hkls in the conventional setting
                unique_millers.append(miller)
                d = abs(reduce(gcd, conv_hkl_list[i]))
                cmiller = tuple([int(i / d) for i in conv_hkl_list[i]])
                unique_millers_conv.append(cmiller)
            else:
                unique_millers.append(miller)
                unique_millers_conv.append(miller)

    return unique_millers_conv

Response: Returns all symmetrically distinct indices below a certain max - index for a given structure.


Instruction:
How would you code a function in Python 3 to
return the Miller index from setting A to B using a transformation matrix .

Response:
def hkl_transformation(transf, miller_index):
    """
    Returns the Miller index from setting
    A to B using a transformation matrix
    Args:
        transf (3x3 array): The transformation matrix
            that transforms a lattice of A to B
        miller_index ([h, k, l]): Miller index to transform to setting B
    """
    # Get a matrix of whole numbers (ints)
    lcm = lambda a, b: a * b // math.gcd(a, b)
    reduced_transf = reduce(lcm, [int(1 / i) for i in itertools.chain(*transf) if i != 0]) * transf
    reduced_transf = reduced_transf.astype(int)

    # perform the transformation
    t_hkl = np.dot(reduced_transf, miller_index)
    d = abs(reduce(gcd, t_hkl))
    t_hkl = np.array([int(i / d) for i in t_hkl])

    # get mostly positive oriented Miller index
    if len([i for i in t_hkl if i < 0]) > 1:
        t_hkl *= -1

    return tuple(t_hkl)


Instruction:
Can you tell what is the following Python 3 function doing
def generate_all_slabs(structure, max_index, min_slab_size, min_vacuum_size,
                       bonds=None, tol=1e-3, max_broken_bonds=0,
                       lll_reduce=False, center_slab=False, primitive=True,
                       max_normal_search=None, symmetrize=False, repair=False,
                       include_reconstructions=False, in_unit_planes=False):
    """
    A function that finds all different slabs up to a certain miller index.
    Slabs oriented under certain Miller indices that are equivalent to other
    slabs in other Miller indices are filtered out using symmetry operations
    to get rid of any repetitive slabs. For example, under symmetry operations,
    CsCl has equivalent slabs in the (0,0,1), (0,1,0), and (1,0,0) direction.

    Args:
        structure (Structure): Initial input structure. Note that to
                ensure that the miller indices correspond to usual
                crystallographic definitions, you should supply a conventional
                unit cell structure.
        max_index (int): The maximum Miller index to go up to.
        min_slab_size (float): In Angstroms
        min_vacuum_size (float): In Angstroms
        bonds ({(specie1, specie2): max_bond_dist}: bonds are
            specified as a dict of tuples: float of specie1, specie2
            and the max bonding distance. For example, PO4 groups may be
            defined as {("P", "O"): 3}.
        tol (float): Threshold parameter in fcluster in order to check
            if two atoms are lying on the same plane. Default thresh set
            to 0.1 Angstrom in the direction of the surface normal.
        max_broken_bonds (int): Maximum number of allowable broken bonds
            for the slab. Use this to limit # of slabs (some structures
            may have a lot of slabs). Defaults to zero, which means no
            defined bonds must be broken.
        lll_reduce (bool): Whether to perform an LLL reduction on the
            eventual structure.
        center_slab (bool): Whether to center the slab in the cell with
            equal vacuum spacing from the top and bottom.
        primitive (bool): Whether to reduce any generated slabs to a
            primitive cell (this does **not** mean the slab is generated
            from a primitive cell, it simply means that after slab
            generation, we attempt to find shorter lattice vectors,
            which lead to less surface area and smaller cells).
        max_normal_search (int): If set to a positive integer, the code will
            conduct a search for a normal lattice vector that is as
            perpendicular to the surface as possible by considering
            multiples linear combinations of lattice vectors up to
            max_normal_search. This has no bearing on surface energies,
            but may be useful as a preliminary step to generating slabs
            for absorption and other sizes. It is typical that this will
            not be the smallest possible cell for simulation. Normality
            is not guaranteed, but the oriented cell will have the c
            vector as normal as possible (within the search range) to the
            surface. A value of up to the max absolute Miller index is
            usually sufficient.
        symmetrize (bool): Whether or not to ensure the surfaces of the
            slabs are equivalent.
        repair (bool): Whether to repair terminations with broken bonds
            or just omit them
        include_reconstructions (bool): Whether to include reconstructed
            slabs available in the reconstructions_archive.json file.
    """
    all_slabs = []

    for miller in get_symmetrically_distinct_miller_indices(structure,
                                                            max_index):
        gen = SlabGenerator(structure, miller, min_slab_size,
                            min_vacuum_size, lll_reduce=lll_reduce,
                            center_slab=center_slab, primitive=primitive,
                            max_normal_search=max_normal_search,
                            in_unit_planes=in_unit_planes)
        slabs = gen.get_slabs(bonds=bonds, tol=tol, symmetrize=symmetrize,
                              max_broken_bonds=max_broken_bonds, repair=repair)

        if len(slabs) > 0:
            logger.debug("%s has %d slabs... " % (miller, len(slabs)))
            all_slabs.extend(slabs)

    if include_reconstructions:
        sg = SpacegroupAnalyzer(structure)
        symbol = sg.get_space_group_symbol()
        # enumerate through all posisble reconstructions in the
        # archive available for this particular structure (spacegroup)
        for name, instructions in reconstructions_archive.items():
            if "base_reconstruction" in instructions.keys():
                instructions = reconstructions_archive[instructions["base_reconstruction"]]
            if instructions["spacegroup"]["symbol"] == symbol:
                # check if this reconstruction has a max index
                # equal or less than the given max index
                if max(instructions["miller_index"]) > max_index:
                    continue
                recon = ReconstructionGenerator(structure, min_slab_size,
                                                min_vacuum_size, name)
                all_slabs.extend(recon.build_slabs())

    return all_slabs

Response: Generates all the slab tables that are part of a particular Miller index.


Instruction:
How would you code a function in Python 3 to
function to get the regions of the slab.

Response:
def get_slab_regions(slab, blength=3.5):
    """
    Function to get the ranges of the slab regions. Useful for discerning where
    the slab ends and vacuum begins if the slab is not fully within the cell
    Args:
        slab (Structure): Structure object modelling the surface
        blength (float, Ang): The bondlength between atoms. You generally
            want this value to be larger than the actual bondlengths in
            order to find atoms that are part of the slab
    """

    fcoords, indices, all_indices = [], [], []
    for site in slab:
        # find sites with c < 0 (noncontiguous)
        neighbors = slab.get_neighbors(site, blength, include_index=True,
                                       include_image=True)
        for nn in neighbors:
            if nn[0].frac_coords[2] < 0:
                # sites are noncontiguous within cell
                fcoords.append(nn[0].frac_coords[2])
                indices.append(nn[-2])
                if nn[-2] not in all_indices:
                    all_indices.append(nn[-2])

    if fcoords:
        # If slab is noncontiguous, locate the lowest
        # site within the upper region of the slab
        while fcoords:
            last_fcoords = copy.copy(fcoords)
            last_indices = copy.copy(indices)
            site = slab[indices[fcoords.index(min(fcoords))]]
            neighbors = slab.get_neighbors(site, blength, include_index=True,
                                           include_image=True)
            fcoords, indices = [], []
            for nn in neighbors:
                if 1 > nn[0].frac_coords[2] > 0 and \
                                nn[0].frac_coords[2] < site.frac_coords[2]:
                    # sites are noncontiguous within cell
                    fcoords.append(nn[0].frac_coords[2])
                    indices.append(nn[-2])
                    if nn[-2] not in all_indices:
                        all_indices.append(nn[-2])

        # Now locate the highest site within the lower region of the slab
        upper_fcoords = []
        for site in slab:
            if all([nn[-1] not in all_indices for nn in
                    slab.get_neighbors(site, blength,
                                       include_index=True)]):
                upper_fcoords.append(site.frac_coords[2])
        coords = copy.copy(last_fcoords) if not fcoords else copy.copy(fcoords)
        min_top = slab[last_indices[coords.index(min(coords))]].frac_coords[2]
        ranges = [[0, max(upper_fcoords)], [min_top, 1]]
    else:
        # If the entire slab region is within the slab cell, just
        # set the range as the highest and lowest site in the slab
        sorted_sites = sorted(slab, key=lambda site: site.frac_coords[2])
        ranges = [[sorted_sites[0].frac_coords[2],
                   sorted_sites[-1].frac_coords[2]]]

    return ranges


Instruction:
How would you implement a function in Python 3 that
gets the Miller index of a plane from a list of site coordinates.

Response:
def miller_index_from_sites(lattice, coords, coords_are_cartesian=True,
                            round_dp=4, verbose=True):
    """
    Get the Miller index of a plane from a list of site coordinates.

    A minimum of 3 sets of coordinates are required. If more than 3 sets of
    coordinates are given, the best plane that minimises the distance to all
    points will be calculated.

    Args:
        lattice (list or Lattice): A 3x3 lattice matrix or `Lattice` object (for
            example obtained from Structure.lattice).
        coords (iterable): A list or numpy array of coordinates. Can be
            cartesian or fractional coordinates. If more than three sets of
            coordinates are provided, the best plane that minimises the
            distance to all sites will be calculated.
        coords_are_cartesian (bool, optional): Whether the coordinates are
            in cartesian space. If using fractional coordinates set to False.
        round_dp (int, optional): The number of decimal places to round the
            miller index to.
        verbose (bool, optional): Whether to print warnings.

    Returns:
        (tuple): The Miller index.
    """
    if not isinstance(lattice, Lattice):
        lattice = Lattice(lattice)

    return lattice.get_miller_index_from_coords(
        coords, coords_are_cartesian=coords_are_cartesian, round_dp=round_dp,
        verbose=verbose)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def center_slab(slab):

    # get a reasonable r cutoff to sample neighbors
    bdists = sorted([nn[1] for nn in
                     slab.get_neighbors(slab[0], 10) if nn[1] > 0])
    r = bdists[0] * 3

    all_indices = [i for i, site in enumerate(slab)]

    # check if structure is case 2 or 3, shift all the
    # sites up to the other side until it is case 1
    for site in slab:
        if any([nn[1] > slab.lattice.c for nn
                in slab.get_neighbors(site, r)]):
            shift = 1 - site.frac_coords[2] + 0.05
            slab.translate_sites(all_indices, [0, 0, shift])

    # now the slab is case 1, shift the center of mass of the slab to 0.5
    weights = [s.species.weight for s in slab]
    center_of_mass = np.average(slab.frac_coords,
                                weights=weights, axis=0)
    shift = 0.5 - center_of_mass[2]
    slab.translate_sites(all_indices, [0, 0, shift])

    return slab

Response: This function centers the slab in a specific region.


Instruction:
Can you tell what is the following Python 3 function doing
def get_tasker2_slabs(self, tol=0.01, same_species_only=True):
        sites = list(self.sites)
        slabs = []

        sortedcsites = sorted(sites, key=lambda site: site.c)

        # Determine what fraction the slab is of the total cell size in the
        # c direction. Round to nearest rational number.
        nlayers_total = int(round(self.lattice.c /
                                  self.oriented_unit_cell.lattice.c))
        nlayers_slab = int(round((sortedcsites[-1].c - sortedcsites[0].c)
                                 * nlayers_total))
        slab_ratio = nlayers_slab / nlayers_total

        a = SpacegroupAnalyzer(self)
        symm_structure = a.get_symmetrized_structure()

        def equi_index(site):
            for i, equi_sites in enumerate(symm_structure.equivalent_sites):
                if site in equi_sites:
                    return i
            raise ValueError("Cannot determine equi index!")

        for surface_site, shift in [(sortedcsites[0], slab_ratio),
                                    (sortedcsites[-1], -slab_ratio)]:
            tomove = []
            fixed = []
            for site in sites:
                if abs(site.c - surface_site.c) < tol and (
                        (not same_species_only) or
                        site.species == surface_site.species):
                    tomove.append(site)
                else:
                    fixed.append(site)

            # Sort and group the sites by the species and symmetry equivalence
            tomove = sorted(tomove, key=lambda s: equi_index(s))

            grouped = [list(sites) for k, sites in itertools.groupby(
                tomove, key=lambda s: equi_index(s))]

            if len(tomove) == 0 or any([len(g) % 2 != 0 for g in grouped]):
                warnings.warn("Odd number of sites to divide! Try changing "
                              "the tolerance to ensure even division of "
                              "sites or create supercells in a or b directions "
                              "to allow for atoms to be moved!")
                continue
            combinations = []
            for g in grouped:
                combinations.append(
                    [c for c in itertools.combinations(g, int(len(g) / 2))])

            for selection in itertools.product(*combinations):
                species = [site.species for site in fixed]
                fcoords = [site.frac_coords for site in fixed]

                for s in tomove:
                    species.append(s.species)
                    for group in selection:
                        if s in group:
                            fcoords.append(s.frac_coords)
                            break
                    else:
                        # Move unselected atom to the opposite surface.
                        fcoords.append(s.frac_coords + [0, 0, shift])

                # sort by species to put all similar species together.
                sp_fcoord = sorted(zip(species, fcoords), key=lambda x: x[0])
                species = [x[0] for x in sp_fcoord]
                fcoords = [x[1] for x in sp_fcoord]
                slab = Slab(self.lattice, species, fcoords, self.miller_index,
                            self.oriented_unit_cell, self.shift,
                            self.scale_factor, energy=self.energy,
                            reorient_lattice=self.reorient_lattice)
                slabs.append(slab)
        s = StructureMatcher()
        unique = [ss[0] for ss in s.group_structures(slabs)]
        return unique

Response: Returns a list of Tasker 2 corrected slabs.


Instruction:
Write a Python 3 script to
check if slab contains inversion symmetry.

Response:
def is_symmetric(self, symprec=0.1):
        """
        Checks if slab is symmetric, i.e., contains inversion symmetry.

        Args:
            symprec (float): Symmetry precision used for SpaceGroup analyzer.

        Returns:
            (bool) Whether slab contains inversion symmetry.
        """

        sg = SpacegroupAnalyzer(self, symprec=symprec)
        return sg.is_laue()


Instruction:
Can you write a function in Python 3 where it
returns a sorted copy of the structure.

Response:
def get_sorted_structure(self, key=None, reverse=False):
        """
        Get a sorted copy of the structure. The parameters have the same
        meaning as in list.sort. By default, sites are sorted by the
        electronegativity of the species. Note that Slab has to override this
        because of the different __init__ args.

        Args:
            key: Specifies a function of one argument that is used to extract
                a comparison key from each list element: key=str.lower. The
                default value is None (compare the elements directly).
            reverse (bool): If set to True, then the list elements are sorted
                as if each comparison were reversed.
        """
        sites = sorted(self, key=key, reverse=reverse)
        s = Structure.from_sites(sites)
        return Slab(s.lattice, s.species_and_occu, s.frac_coords,
                    self.miller_index, self.oriented_unit_cell, self.shift,
                    self.scale_factor, site_properties=s.site_properties,
                    reorient_lattice=self.reorient_lattice)


Instruction:
Make a summary of the following Python 3 code
def copy(self, site_properties=None, sanitize=False):
        props = self.site_properties
        if site_properties:
            props.update(site_properties)
        return Slab(self.lattice, self.species_and_occu, self.frac_coords,
                    self.miller_index, self.oriented_unit_cell, self.shift,
                    self.scale_factor, site_properties=props,
                    reorient_lattice=self.reorient_lattice)

Response: Returns a copy of the structure with optionally new site properties and sanitized.


Instruction:
Write a Python 3 function for
calculating the dipole of the Slab in the direction of the surface.

Response:
def dipole(self):
        """
        Calculates the dipole of the Slab in the direction of the surface
        normal. Note that the Slab must be oxidation state-decorated for this
        to work properly. Otherwise, the Slab will always have a dipole of 0.
        """
        dipole = np.zeros(3)
        mid_pt = np.sum(self.cart_coords, axis=0) / len(self)
        normal = self.normal
        for site in self:
            charge = sum([getattr(sp, "oxi_state", 0) * amt
                          for sp, amt in site.species.items()])
            dipole += charge * np.dot(site.coords - mid_pt, normal) * normal
        return dipole


Instruction:
Can you generate a brief explanation for the following Python 3 code
def is_polar(self, tol_dipole_per_unit_area=1e-3):
        dip_per_unit_area = self.dipole / self.surface_area
        return np.linalg.norm(dip_per_unit_area) > tol_dipole_per_unit_area

Response: Checks whether the surface is polar by computing the dipole per unit area of the Slab.


Instruction:
How would you explain what the following Python 3 function does
def normal(self):
        normal = np.cross(self.lattice.matrix[0], self.lattice.matrix[1])
        normal /= np.linalg.norm(normal)
        return normal

Response: Calculates the surface normal vector of the slab


Instruction:
Make a summary of the following Python 3 code
def surface_area(self):
        m = self.lattice.matrix
        return np.linalg.norm(np.cross(m[0], m[1]))

Response: Calculates the surface area of the slab object


Instruction:
How would you implement a function in Python 3 that
calculates the center of mass of the slab

Response:
def center_of_mass(self):
        """
        Calculates the center of mass of the slab
        """
        weights = [s.species.weight for s in self]
        center_of_mass = np.average(self.frac_coords,
                                    weights=weights, axis=0)
        return center_of_mass


Instruction:
Can you generate the documentation for the following Python 3 function
def add_adsorbate_atom(self, indices, specie, distance):
        # Let's do the work in cartesian coords
        center = np.sum([self[i].coords for i in indices], axis=0) / len(
            indices)

        coords = center + self.normal * distance / np.linalg.norm(self.normal)

        self.append(specie, coords, coords_are_cartesian=True)

Response: Adds an adsorbate atom to the slab structure.


Instruction:
Explain what the following Python 3 code does
def get_surface_sites(self, tag=False):

        from pymatgen.analysis.local_env import VoronoiNN

        # Get a dictionary of coordination numbers
        # for each distinct site in the structure
        a = SpacegroupAnalyzer(self.oriented_unit_cell)
        ucell = a.get_symmetrized_structure()
        cn_dict = {}
        v = VoronoiNN()
        unique_indices = [equ[0] for equ in ucell.equivalent_indices]

        for i in unique_indices:
            el = ucell[i].species_string
            if el not in cn_dict.keys():
                cn_dict[el] = []
            # Since this will get the cn as a result of the weighted polyhedra, the
            # slightest difference in cn will indicate a different environment for a
            # species, eg. bond distance of each neighbor or neighbor species. The
            # decimal place to get some cn to be equal.
            cn = v.get_cn(ucell, i, use_weights=True)
            cn = float('%.5f' %(round(cn, 5)))
            if cn not in cn_dict[el]:
                cn_dict[el].append(cn)

        v = VoronoiNN()

        surf_sites_dict, properties = {"top": [], "bottom": []}, []
        for i, site in enumerate(self):
            # Determine if site is closer to the top or bottom of the slab
            top = True if site.frac_coords[2] > self.center_of_mass[2] else False

            try:
                # A site is a surface site, if its environment does
                # not fit the environment of other sites
                cn = float('%.5f' %(round(v.get_cn(self, i, use_weights=True), 5)))
                if cn < min(cn_dict[site.species_string]):
                    properties.append(True)
                    key = "top" if top else "bottom"
                    surf_sites_dict[key].append([site, i])
                else:
                    properties.append(False)
            except RuntimeError:
                # or if pathological error is returned, indicating a surface site
                properties.append(True)
                key = "top" if top else "bottom"
                surf_sites_dict[key].append([site, i])

        if tag:
            self.add_site_property("is_surf_site", properties)
        return surf_sites_dict

Response: Returns the surface sites and their indices in a dictionary.


Instruction:
How would you code a function in Python 3 to
check if we have same number of equivalent sites on both surfaces.

Response:
def have_equivalent_surfaces(self):
        """
        Check if we have same number of equivalent sites on both surfaces.
        This is an alternative to checking Laue symmetry (is_symmetric())
        if we want to ensure both surfaces in the slab are the same
        """

        # tag the sites as either surface sites or not
        surf_sites_dict = self.get_surface_sites(tag=True)

        a = SpacegroupAnalyzer(self)
        symm_structure = a.get_symmetrized_structure()

        # ensure each site on one surface has a
        # corresponding equivalent site on the other
        equal_surf_sites = []
        for equ in symm_structure.equivalent_sites:
            # Top and bottom are arbitrary, we will just determine
            # if one site is on one side of the slab or the other
            top, bottom = 0, 0
            for s in equ:
                if s.is_surf_site:
                    if s.frac_coords[2] > self.center_of_mass[2]:
                        top += 1
                    else:
                        bottom += 1
            # Check to see if the number of equivalent sites
            # on one side of the slab are equal to the other
            equal_surf_sites.append(top == bottom)

        return all(equal_surf_sites)


Instruction:
Given the following Python 3 function, write the documentation
def get_symmetric_site(self, point, cartesian=False):

        sg = SpacegroupAnalyzer(self)
        ops = sg.get_symmetry_operations(cartesian=cartesian)

        # Each operation on a point will return an equivalent point.
        # We want to find the point on the other side of the slab.
        for op in ops:
            slab = self.copy()
            site2 = op.operate(point)
            if "%.6f" % (site2[2]) == "%.6f" % (point[2]):
                continue

            # Add dummy site to check the overall structure is symmetric
            slab.append("O", point, coords_are_cartesian=cartesian)
            slab.append("O", site2, coords_are_cartesian=cartesian)
            sg = SpacegroupAnalyzer(slab)
            if sg.is_laue():
                break
            else:
                # If not symmetric, remove the two added
                # sites and try another symmetry operator
                slab.remove_sites([len(slab) - 1])
                slab.remove_sites([len(slab) - 1])

        return site2

Response: This method returns the symmetric site of the overall structure.


Instruction:
Implement a function in Python 3 to
class method for adding a site at a specified point in a slab. Will add the corresponding site on the other side of the slab to maintain equivalent surfaces. Arg: specie (str): The specie to add point (coords): The coordinate of the site in the slab to add. coords_are_cartesian (bool): Is the point in cartesian coordinates Returns: (Slab): The modified slab

Response:
def symmetrically_add_atom(self, specie, point, coords_are_cartesian=False):

        """
        Class method for adding a site at a specified point in a slab.
            Will add the corresponding site on the other side of the
            slab to maintain equivalent surfaces.

        Arg:
            specie (str): The specie to add
            point (coords): The coordinate of the site in the slab to add.
            coords_are_cartesian (bool): Is the point in cartesian coordinates

        Returns:
            (Slab): The modified slab
        """

        # For now just use the species of the
        # surface atom as the element to add

        # Get the index of the corresponding site at the bottom
        point2 = self.get_symmetric_site(point, cartesian=coords_are_cartesian)

        self.append(specie, point, coords_are_cartesian=coords_are_cartesian)
        self.append(specie, point2, coords_are_cartesian=coords_are_cartesian)


Instruction:
Write a Python 3 script to
class method for removing sites corresponding to a list of indices. Will remove the corresponding site on the other side of the slab to maintain equivalent surfaces. Arg: indices ([indices]): The indices of the sites in the slab to remove.

Response:
def symmetrically_remove_atoms(self, indices):

        """
        Class method for removing sites corresponding to a list of indices.
            Will remove the corresponding site on the other side of the
            slab to maintain equivalent surfaces.

        Arg:
            indices ([indices]): The indices of the sites
                in the slab to remove.
        """

        slabcopy = SpacegroupAnalyzer(self.copy()).get_symmetrized_structure()
        points = [slabcopy[i].frac_coords for i in indices]
        removal_list = []

        for pt in points:
            # Get the index of the original site on top
            cart_point = slabcopy.lattice.get_cartesian_coords(pt)
            dist = [site.distance_from_point(cart_point) for site in slabcopy]
            site1 = dist.index(min(dist))

            # Get the index of the corresponding site at the bottom
            for i, eq_sites in enumerate(slabcopy.equivalent_sites):
                if slabcopy[site1] in eq_sites:
                    eq_indices = slabcopy.equivalent_indices[i]
                    break
            i1 = eq_indices[eq_sites.index(slabcopy[site1])]

            for i2 in eq_indices:
                if i2 == i1:
                    continue
                if slabcopy[i2].frac_coords[2] == slabcopy[i1].frac_coords[2]:
                    continue
                # Test site remove to see if it results in symmetric slab
                s = self.copy()
                s.remove_sites([i1, i2])
                if s.is_symmetric():
                    removal_list.extend([i1, i2])
                    break

        # If expected, 2 atoms are removed per index
        if len(removal_list) == 2*len(indices):
            self.remove_sites(removal_list)
        else:
            warnings.warn("Equivalent sites could not be found for removal for all indices. Surface unchanged.")


Instruction:
Here you have a function in Python 3, explain what it does
def get_slab(self, shift=0, tol=0.1, energy=None):

        h = self._proj_height
        p = h/self.parent.lattice.d_hkl(self.miller_index)
        if self.in_unit_planes:
            nlayers_slab = int(math.ceil(self.min_slab_size / p))
            nlayers_vac = int(math.ceil(self.min_vac_size / p))
        else:
            nlayers_slab = int(math.ceil(self.min_slab_size / h))
            nlayers_vac = int(math.ceil(self.min_vac_size / h))
        nlayers = nlayers_slab + nlayers_vac

        species = self.oriented_unit_cell.species_and_occu
        props = self.oriented_unit_cell.site_properties
        props = {k: v * nlayers_slab for k, v in props.items()}
        frac_coords = self.oriented_unit_cell.frac_coords
        frac_coords = np.array(frac_coords) + np.array([0, 0, -shift])[None, :]
        frac_coords -= np.floor(frac_coords)
        a, b, c = self.oriented_unit_cell.lattice.matrix
        new_lattice = [a, b, nlayers * c]
        frac_coords[:, 2] = frac_coords[:, 2] / nlayers
        all_coords = []
        for i in range(nlayers_slab):
            fcoords = frac_coords.copy()
            fcoords[:, 2] += i / nlayers
            all_coords.extend(fcoords)

        slab = Structure(new_lattice, species * nlayers_slab, all_coords,
                         site_properties=props)

        scale_factor = self.slab_scale_factor
        # Whether or not to orthogonalize the structure
        if self.lll_reduce:
            lll_slab = slab.copy(sanitize=True)
            mapping = lll_slab.lattice.find_mapping(slab.lattice)
            scale_factor = np.dot(mapping[2], scale_factor)
            slab = lll_slab

        # Whether or not to center the slab layer around the vacuum
        if self.center_slab:
            avg_c = np.average([c[2] for c in slab.frac_coords])
            slab.translate_sites(list(range(len(slab))), [0, 0, 0.5 - avg_c])

        if self.primitive:
            prim = slab.get_primitive_structure(tolerance=tol)
            if energy is not None:
                energy = prim.volume / slab.volume * energy
            slab = prim

        # Reorient the lattice to get the correct reduced cell
        ouc = self.oriented_unit_cell.copy()
        if self.primitive:
            #find a reduced ouc
            slab_l = slab.lattice
            ouc = ouc.get_primitive_structure(constrain_latt={"a": slab_l.a, "b": slab_l.b,
                                                              "alpha": slab_l.alpha,
                                                              "beta": slab_l.beta,
                                                              "gamma": slab_l.gamma})

        return Slab(slab.lattice, slab.species_and_occu,
                    slab.frac_coords, self.miller_index,
                    ouc, shift, scale_factor, energy=energy,
                    site_properties=slab.site_properties,
                    reorient_lattice=self.reorient_lattice)

Response: This method generates a slab based on the given shift value and the given energy.


Instruction:
Make a summary of the following Python 3 code
def get_slabs(self, bonds=None, ftol=0.1, tol=0.1, max_broken_bonds=0,
                  symmetrize=False, repair=False):
        """
        This method returns a list of slabs that are generated using the list of
        shift values from the method, _calculate_possible_shifts(). Before the
        shifts are used to create the slabs however, if the user decides to take
        into account whether or not a termination will break any polyhedral
        structure (bonds is not None), this method will filter out any shift
        values that do so.

        Args:
            bonds ({(specie1, specie2): max_bond_dist}: bonds are
                specified as a dict of tuples: float of specie1, specie2
                and the max bonding distance. For example, PO4 groups may be
                defined as {("P", "O"): 3}.
            tol (float): General tolerance paramter for getting primitive
                cells and matching structures
            ftol (float): Threshold parameter in fcluster in order to check
                if two atoms are lying on the same plane. Default thresh set
                to 0.1 Angstrom in the direction of the surface normal.
            max_broken_bonds (int): Maximum number of allowable broken bonds
                for the slab. Use this to limit # of slabs (some structures
                may have a lot of slabs). Defaults to zero, which means no
                defined bonds must be broken.
            symmetrize (bool): Whether or not to ensure the surfaces of the
                slabs are equivalent.
            repair (bool): Whether to repair terminations with broken bonds
                or just omit them. Set to False as repairing terminations can
                lead to many possible slabs as oppose to just omitting them.

        Returns:
            ([Slab]) List of all possible terminations of a particular surface.
            Slabs are sorted by the # of bonds broken.
        """
        c_ranges = set() if bonds is None else self._get_c_ranges(bonds)

        slabs = []
        for shift in self._calculate_possible_shifts(tol=ftol):
            bonds_broken = 0
            for r in c_ranges:
                if r[0] <= shift <= r[1]:
                    bonds_broken += 1
            slab = self.get_slab(shift, tol=tol, energy=bonds_broken)
            if bonds_broken <= max_broken_bonds:
                slabs.append(slab)
            elif repair:
                # If the number of broken bonds is exceeded,
                # we repair the broken bonds on the slab
                slabs.append(self.repair_broken_bonds(slab, bonds))

        # Further filters out any surfaces made that might be the same
        m = StructureMatcher(ltol=tol, stol=tol, primitive_cell=False,
                             scale=False)

        new_slabs = []
        for g in m.group_structures(slabs):
            # For each unique termination, symmetrize the
            # surfaces by removing sites from the bottom.
            if symmetrize:
                slabs = self.nonstoichiometric_symmetrized_slab(g[0])
                new_slabs.extend(slabs)
            else:
                new_slabs.append(g[0])

        match = StructureMatcher(ltol=tol, stol=tol, primitive_cell=False,
                                 scale=False)
        new_slabs = [g[0] for g in match.group_structures(new_slabs)]

        return sorted(new_slabs, key=lambda s: s.energy)

Response: This method returns a list of all possible terminations of a particular slab.


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

        for pair in bonds.keys():
            blength = bonds[pair]

            # First lets determine which element should be the
            # reference (center element) to determine broken bonds.
            # e.g. P for a PO4 bond. Find integer coordination
            # numbers of the pair of elements wrt to each other
            cn_dict = {}
            for i, el in enumerate(pair):
                cnlist = []
                for site in self.oriented_unit_cell:
                    poly_coord = 0
                    if site.species_string == el:

                        for nn in self.oriented_unit_cell.get_neighbors(
                                site, blength):
                            if nn[0].species_string == pair[i-1]:
                                poly_coord += 1
                    cnlist.append(poly_coord)
                cn_dict[el] = cnlist

            # We make the element with the higher coordination our reference
            if max(cn_dict[pair[0]]) > max(cn_dict[pair[1]]):
                element1, element2 = pair
            else:
                element2, element1 = pair

            for i, site in enumerate(slab):
                # Determine the coordination of our reference
                if site.species_string == element1:
                    poly_coord = 0
                    for neighbor in slab.get_neighbors(site, blength):
                        poly_coord += 1 if neighbor[0].species_string == element2 else 0

                    # suppose we find an undercoordinated reference atom
                    if poly_coord not in cn_dict[element1]:
                        # We get the reference atom of the broken bonds
                        # (undercoordinated), move it to the other surface
                        slab = self.move_to_other_side(slab, [i])

                        # find its NNs with the corresponding
                        # species it should be coordinated with
                        neighbors = slab.get_neighbors(slab[i], blength,
                                                       include_index=True)
                        tomove = [nn[2] for nn in neighbors if
                                  nn[0].species_string == element2]
                        tomove.append(i)
                        # and then move those NNs along with the central
                        # atom back to the other side of the slab again
                        slab = self.move_to_other_side(slab, tomove)

        return slab

Response: This method will find undercoordinated atoms due to the slab and move them to the other surface.


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

        slabs = self.get_unreconstructed_slabs()
        recon_slabs = []

        for slab in slabs:
            d = get_d(slab)
            top_site = sorted(slab, key=lambda site: site.frac_coords[2])[-1].coords

            # Remove any specified sites
            if "points_to_remove" in self.reconstruction_json.keys():
                pts_to_rm = copy.deepcopy(self.reconstruction_json["points_to_remove"])
                for p in pts_to_rm:
                    p[2] = slab.lattice.get_fractional_coords([top_site[0], top_site[1],
                                                               top_site[2]+p[2]*d])[2]
                    cart_point = slab.lattice.get_cartesian_coords(p)
                    dist = [site.distance_from_point(cart_point) for site in slab]
                    site1 = dist.index(min(dist))
                    slab.symmetrically_remove_atoms([site1])

            # Add any specified sites
            if "points_to_add" in self.reconstruction_json.keys():
                pts_to_add = copy.deepcopy(self.reconstruction_json["points_to_add"])
                for p in pts_to_add:
                    p[2] = slab.lattice.get_fractional_coords([top_site[0], top_site[1],
                                                               top_site[2]+p[2]*d])[2]
                    slab.symmetrically_add_atom(slab[0].specie, p)

            slab.reconstruction = self.name
            setattr(slab, "recon_trans_matrix", self.trans_matrix)

            # Get the oriented_unit_cell with the same axb area.
            ouc = slab.oriented_unit_cell.copy()
            ouc.make_supercell(self.trans_matrix)
            slab.oriented_unit_cell = ouc
            recon_slabs.append(slab)

        return recon_slabs

Response: Builds the unreconstructed slab by the specified parameters.


Instruction:
Explain what the following Python 3 code does
def get_unreconstructed_slabs(self):

        """
        Generates the unreconstructed or pristine super slab.
        """

        slabs = []
        for slab in SlabGenerator(**self.slabgen_params).get_slabs():
            slab.make_supercell(self.trans_matrix)
            slabs.append(slab)
        return slabs

Response: Generates the unreconstructed or pristine super slab.


Instruction:
Can you generate the documentation for the following Python 3 function
def from_file(filename, check_for_POTCAR=True, read_velocities=True):
        dirname = os.path.dirname(os.path.abspath(filename))
        names = None
        if check_for_POTCAR:
            potcars = glob.glob(os.path.join(dirname, "*POTCAR*"))
            if potcars:
                try:
                    potcar = Potcar.from_file(sorted(potcars)[0])
                    names = [sym.split("_")[0] for sym in potcar.symbols]
                    [get_el_sp(n) for n in names]  # ensure valid names
                except:
                    names = None
        with zopen(filename, "rt") as f:
            return Poscar.from_string(f.read(), names,
                                      read_velocities=read_velocities)

Response: Reads a Poscar from a file.


Instruction:
Given the following Python 3 function, write the documentation
def from_string(data, default_names=None, read_velocities=True):
        # "^\s*$" doesn't match lines with no whitespace
        chunks = re.split(r"\n\s*\n", data.rstrip(), flags=re.MULTILINE)
        try:
            if chunks[0] == "":
                chunks.pop(0)
                chunks[0] = "\n" + chunks[0]
        except IndexError:
            raise ValueError("Empty POSCAR")

        # Parse positions
        lines = tuple(clean_lines(chunks[0].split("\n"), False))
        comment = lines[0]
        scale = float(lines[1])
        lattice = np.array([[float(i) for i in line.split()]
                            for line in lines[2:5]])
        if scale < 0:
            # In vasp, a negative scale factor is treated as a volume. We need
            # to translate this to a proper lattice vector scaling.
            vol = abs(det(lattice))
            lattice *= (-scale / vol) ** (1 / 3)
        else:
            lattice *= scale

        vasp5_symbols = False
        try:
            natoms = [int(i) for i in lines[5].split()]
            ipos = 6
        except ValueError:
            vasp5_symbols = True
            symbols = lines[5].split()

            """
            Atoms and number of atoms in POSCAR written with vasp appear on
            multiple lines when atoms of the same type are not grouped together
            and more than 20 groups are then defined ...

            Example :

            Cr16 Fe35 Ni2
               1.00000000000000
                 8.5415010000000002   -0.0077670000000000   -0.0007960000000000
                -0.0077730000000000    8.5224019999999996    0.0105580000000000
                -0.0007970000000000    0.0105720000000000    8.5356889999999996
               Fe   Cr   Fe   Cr   Fe   Cr   Fe   Cr   Fe   Cr   Fe   Cr   Fe   Cr   Fe   Ni   Fe   Cr   Fe   Cr
               Fe   Ni   Fe   Cr   Fe
                 1     1     2     4     2     1     1     1     2     1     1     1     4     1     1     1     5     3     6     1
                 2     1     3     2     5
            Direct
              ...
            """
            nlines_symbols = 1
            for nlines_symbols in range(1, 11):
                try:
                    int(lines[5+nlines_symbols].split()[0])
                    break
                except ValueError:
                    pass
            for iline_symbols in range(6, 5+nlines_symbols):
                symbols.extend(lines[iline_symbols].split())
            natoms = []
            iline_natoms_start = 5+nlines_symbols
            for iline_natoms in range(iline_natoms_start,
                                      iline_natoms_start+nlines_symbols):
                natoms.extend([int(i) for i in lines[iline_natoms].split()])
            atomic_symbols = list()
            for i in range(len(natoms)):
                atomic_symbols.extend([symbols[i]] * natoms[i])
            ipos = 5+2*nlines_symbols

        postype = lines[ipos].split()[0]

        sdynamics = False
        # Selective dynamics
        if postype[0] in "sS":
            sdynamics = True
            ipos += 1
            postype = lines[ipos].split()[0]

        cart = postype[0] in "cCkK"
        nsites = sum(natoms)

        # If default_names is specified (usually coming from a POTCAR), use
        # them. This is in line with Vasp"s parsing order that the POTCAR
        # specified is the default used.
        if default_names:
            try:
                atomic_symbols = []
                for i in range(len(natoms)):
                    atomic_symbols.extend([default_names[i]] * natoms[i])
                vasp5_symbols = True
            except IndexError:
                pass

        if not vasp5_symbols:
            ind = 3 if not sdynamics else 6
            try:
                # Check if names are appended at the end of the coordinates.
                atomic_symbols = [l.split()[ind]
                                  for l in lines[ipos + 1:ipos + 1 + nsites]]
                # Ensure symbols are valid elements
                if not all([Element.is_valid_symbol(sym)
                            for sym in atomic_symbols]):
                    raise ValueError("Non-valid symbols detected.")
                vasp5_symbols = True
            except (ValueError, IndexError):
                # Defaulting to false names.
                atomic_symbols = []
                for i in range(len(natoms)):
                    sym = Element.from_Z(i + 1).symbol
                    atomic_symbols.extend([sym] * natoms[i])
                warnings.warn("Elements in POSCAR cannot be determined. "
                              "Defaulting to false names %s." %
                              " ".join(atomic_symbols))

        # read the atomic coordinates
        coords = []
        selective_dynamics = list() if sdynamics else None
        for i in range(nsites):
            toks = lines[ipos + 1 + i].split()
            crd_scale = scale if cart else 1
            coords.append([float(j) * crd_scale for j in toks[:3]])
            if sdynamics:
                selective_dynamics.append([tok.upper()[0] == "T"
                                           for tok in toks[3:6]])

        struct = Structure(lattice, atomic_symbols, coords,
                           to_unit_cell=False, validate_proximity=False,
                           coords_are_cartesian=cart)

        if read_velocities:
            # Parse velocities if any
            velocities = []
            if len(chunks) > 1:
                for line in chunks[1].strip().split("\n"):
                    velocities.append([float(tok) for tok in line.split()])

            # Parse the predictor-corrector data
            predictor_corrector = []
            predictor_corrector_preamble = None

            if len(chunks) > 2:
                lines = chunks[2].strip().split("\n")
                # There are 3 sets of 3xN Predictor corrector parameters
                # So can't be stored as a single set of "site_property"

                # First line in chunk is a key in CONTCAR
                # Second line is POTIM
                # Third line is the thermostat parameters
                predictor_corrector_preamble = (lines[0] + "\n" + lines[1]
                                                + "\n" + lines[2])
                # Rest is three sets of parameters, each set contains
                # x, y, z predictor-corrector parameters for every atom in orde
                lines = lines[3:]
                for st in range(nsites):
                    d1 = [float(tok) for tok in lines[st].split()]
                    d2 = [float(tok) for tok in lines[st+nsites].split()]
                    d3 = [float(tok) for tok in lines[st+2*nsites].split()]
                    predictor_corrector.append([d1,d2,d3])
        else:
            velocities = None
            predictor_corrector = None
            predictor_corrector_preamble = None

        return Poscar(struct, comment, selective_dynamics, vasp5_symbols,
                      velocities=velocities,
                      predictor_corrector=predictor_corrector,
                      predictor_corrector_preamble=predictor_corrector_preamble)

Response: Reads a Poscar from a string containing a set of elemental properties.


Instruction:
Explain what the following Python 3 code does
def get_string(self, direct=True, vasp4_compatible=False,
                   significant_figures=6):
        """
        Returns a string to be written as a POSCAR file. By default, site
        symbols are written, which means compatibility is for vasp >= 5.

        Args:
            direct (bool): Whether coordinates are output in direct or
                cartesian. Defaults to True.
            vasp4_compatible (bool): Set to True to omit site symbols on 6th
                line to maintain backward vasp 4.x compatibility. Defaults
                to False.
            significant_figures (int): No. of significant figures to
                output all quantities. Defaults to 6. Note that positions are
                output in fixed point, while velocities are output in
                scientific format.

        Returns:
            String representation of POSCAR.
        """

        # This corrects for VASP really annoying bug of crashing on lattices
        # which have triple product < 0. We will just invert the lattice
        # vectors.
        latt = self.structure.lattice
        if np.linalg.det(latt.matrix) < 0:
            latt = Lattice(-latt.matrix)

        format_str = "{{:.{0}f}}".format(significant_figures)
        lines = [self.comment, "1.0"]
        for v in latt.matrix:
            lines.append(" ".join([format_str.format(c) for c in v]))

        if self.true_names and not vasp4_compatible:
            lines.append(" ".join(self.site_symbols))
        lines.append(" ".join([str(x) for x in self.natoms]))
        if self.selective_dynamics:
            lines.append("Selective dynamics")
        lines.append("direct" if direct else "cartesian")

        selective_dynamics = self.selective_dynamics
        for (i, site) in enumerate(self.structure):
            coords = site.frac_coords if direct else site.coords
            line = " ".join([format_str.format(c) for c in coords])
            if selective_dynamics is not None:
                sd = ["T" if j else "F" for j in selective_dynamics[i]]
                line += " %s %s %s" % (sd[0], sd[1], sd[2])
            line += " " + site.species_string
            lines.append(line)

        if self.velocities:
            try:
                lines.append("")
                for v in self.velocities:
                    lines.append(" ".join([format_str.format(i) for i in v]))
            except:
                warnings.warn("Velocities are missing or corrupted.")

        if self.predictor_corrector:
            lines.append("")
            if self.predictor_corrector_preamble:
                lines.append(self.predictor_corrector_preamble)
                pred = np.array(self.predictor_corrector)
                for col in range(3):
                    for z in pred[:,col]:
                        lines.append(" ".join([format_str.format(i) for i in z]))
            else:
                warnings.warn(
                    "Preamble information missing or corrupt. "
                    "Writing Poscar with no predictor corrector data.")

        return "\n".join(lines) + "\n"

Response: Returns a string representation of the structure as a POSCAR file.


Instruction:
Make a summary of the following Python 3 code
def write_file(self, filename, **kwargs):
        with zopen(filename, "wt") as f:
            f.write(self.get_string(**kwargs))

Response: Writes a POSCAR to a file.


Instruction:
Create a Python 3 function to
set the temperature of the entry in the structure.

Response:
def set_temperature(self, temperature):
        """
        Initializes the velocities based on Maxwell-Boltzmann distribution.
        Removes linear, but not angular drift (same as VASP)

        Scales the energies to the exact temperature (microcanonical ensemble)
        Velocities are given in A/fs. This is the vasp default when
        direct/cartesian is not specified (even when positions are given in
        direct coordinates)

        Overwrites imported velocities, if any.

        Args:
            temperature (float): Temperature in Kelvin.
        """
        # mean 0 variance 1
        velocities = np.random.randn(len(self.structure), 3)

        # in AMU, (N,1) array
        atomic_masses = np.array([site.specie.atomic_mass.to("kg")
                                  for site in self.structure])
        dof = 3 * len(self.structure) - 3

        # scale velocities due to atomic masses
        # mean 0 std proportional to sqrt(1/m)
        velocities /= atomic_masses[:, np.newaxis] ** (1 / 2)

        # remove linear drift (net momentum)
        velocities -= np.average(atomic_masses[:, np.newaxis] * velocities,
                                 axis=0) / np.average(atomic_masses)

        # scale velocities to get correct temperature
        energy = np.sum(1 / 2 * atomic_masses *
                        np.sum(velocities ** 2, axis=1))
        scale = (temperature * dof / (2 * energy / const.k)) ** (1 / 2)

        velocities *= scale * 1e-5  # these are in A/fs

        self.temperature = temperature
        try:
            del self.structure.site_properties["selective_dynamics"]
        except KeyError:
            pass

        try:
            del self.structure.site_properties["predictor_corrector"]
        except KeyError:
            pass
        # returns as a list of lists to be consistent with the other
        # initializations

        self.structure.add_site_property("velocities", velocities.tolist())


Instruction:
Explain what the following Python 3 code does
def get_string(self, sort_keys=False, pretty=False):
        keys = self.keys()
        if sort_keys:
            keys = sorted(keys)
        lines = []
        for k in keys:
            if k == "MAGMOM" and isinstance(self[k], list):
                value = []

                if (isinstance(self[k][0], list) or isinstance(self[k][0], Magmom)) and \
                        (self.get("LSORBIT") or self.get("LNONCOLLINEAR")):
                    value.append(" ".join(str(i) for j in self[k] for i in j))
                elif self.get("LSORBIT") or self.get("LNONCOLLINEAR"):
                    for m, g in itertools.groupby(self[k]):
                        value.append("3*{}*{}".format(len(tuple(g)), m))
                else:
                    # float() to ensure backwards compatibility between
                    # float magmoms and Magmom objects
                    for m, g in itertools.groupby(self[k], lambda x: float(x)):
                        value.append("{}*{}".format(len(tuple(g)), m))

                lines.append([k, " ".join(value)])
            elif isinstance(self[k], list):
                lines.append([k, " ".join([str(i) for i in self[k]])])
            else:
                lines.append([k, self[k]])

        if pretty:
            return str(tabulate([[l[0], "=", l[1]] for l in lines],
                                tablefmt="plain"))
        else:
            return str_delimited(lines, None, " = ") + "\n"

Response: Returns a string representation of the INCAR.


Instruction:
Implement a Python 3 function for
reading an Incar object from a string.

Response:
def from_string(string):
        """
        Reads an Incar object from a string.

        Args:
            string (str): Incar string

        Returns:
            Incar object
        """
        lines = list(clean_lines(string.splitlines()))
        params = {}
        for line in lines:
            for sline in line.split(';'):
                m = re.match(r'(\w+)\s*=\s*(.*)', sline.strip())
                if m:
                    key = m.group(1).strip()
                    val = m.group(2).strip()
                    val = Incar.proc_val(key, val)
                    params[key] = val
        return Incar(params)