Instruction:
Implement a function in Python 3 to
handle no rotational symmetry.

Response:
def _proc_no_rot_sym(self):
        """
        Handles molecules with no rotational symmetry. Only possible point
        groups are C1, Cs and Ci.
        """
        self.sch_symbol = "C1"
        if self.is_valid_op(PointGroupAnalyzer.inversion_op):
            self.sch_symbol = "Ci"
            self.symmops.append(PointGroupAnalyzer.inversion_op)
        else:
            for v in self.principal_axes:
                mirror_type = self._find_mirror(v)
                if not mirror_type == "":
                    self.sch_symbol = "Cs"
                    break


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _proc_cyclic(self):
        main_axis, rot = max(self.rot_sym, key=lambda v: v[1])
        self.sch_symbol = "C{}".format(rot)
        mirror_type = self._find_mirror(main_axis)
        if mirror_type == "h":
            self.sch_symbol += "h"
        elif mirror_type == "v":
            self.sch_symbol += "v"
        elif mirror_type == "":
            if self.is_valid_op(SymmOp.rotoreflection(main_axis,
                                                      angle=180 / rot)):
                self.sch_symbol = "S{}".format(2 * rot)

Response: Handles cyclic group molecules.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _proc_dihedral(self):
        main_axis, rot = max(self.rot_sym, key=lambda v: v[1])
        self.sch_symbol = "D{}".format(rot)
        mirror_type = self._find_mirror(main_axis)
        if mirror_type == "h":
            self.sch_symbol += "h"
        elif not mirror_type == "":
            self.sch_symbol += "d"

Response:
Handles dihedral group molecules i. e those with intersecting R2 axes
        and a main axis.


Instruction:
Create a Python 3 function to
test for 2 - fold rotation along the principal axes. Used to handle asymetric top molecules.

Response:
def _check_R2_axes_asym(self):
        """
        Test for 2-fold rotation along the principal axes. Used to handle
        asymetric top molecules.
        """
        for v in self.principal_axes:
            op = SymmOp.from_axis_angle_and_translation(v, 180)
            if self.is_valid_op(op):
                self.symmops.append(op)
                self.rot_sym.append((v, 2))


Instruction:
Write a Python 3 function that can
find the mirror type of the specified axis.

Response:
def _find_mirror(self, axis):
        """
        Looks for mirror symmetry of specified type about axis.  Possible
        types are "h" or "vd".  Horizontal (h) mirrors are perpendicular to
        the axis while vertical (v) or diagonal (d) mirrors are parallel.  v
        mirrors has atoms lying on the mirror plane while d mirrors do
        not.
        """
        mirror_type = ""

        # First test whether the axis itself is the normal to a mirror plane.
        if self.is_valid_op(SymmOp.reflection(axis)):
            self.symmops.append(SymmOp.reflection(axis))
            mirror_type = "h"
        else:
            # Iterate through all pairs of atoms to find mirror
            for s1, s2 in itertools.combinations(self.centered_mol, 2):
                if s1.species == s2.species:
                    normal = s1.coords - s2.coords
                    if np.dot(normal, axis) < self.tol:
                        op = SymmOp.reflection(normal)
                        if self.is_valid_op(op):
                            self.symmops.append(op)
                            if len(self.rot_sym) > 1:
                                mirror_type = "d"
                                for v, r in self.rot_sym:
                                    if not np.linalg.norm(v - axis) < self.tol:
                                        if np.dot(v, normal) < self.tol:
                                            mirror_type = "v"
                                            break
                            else:
                                mirror_type = "v"
                            break

        return mirror_type


Instruction:
Make a summary of the following Python 3 code
def _check_rot_sym(self, axis):
        min_set = self._get_smallest_set_not_on_axis(axis)
        max_sym = len(min_set)
        for i in range(max_sym, 0, -1):
            if max_sym % i != 0:
                continue
            op = SymmOp.from_axis_angle_and_translation(axis, 360 / i)
            rotvalid = self.is_valid_op(op)
            if rotvalid:
                self.symmops.append(op)
                self.rot_sym.append((axis, i))
                return i
        return 1

Response: Checks if the rotational symmetry about supplied axis is valid.


Instruction:
Write a Python 3 function that can
check if R2 axes perpendicular to unique axis.

Response:
def _check_perpendicular_r2_axis(self, axis):
        """
        Checks for R2 axes perpendicular to unique axis.  For handling
        symmetric top molecules.
        """
        min_set = self._get_smallest_set_not_on_axis(axis)
        for s1, s2 in itertools.combinations(min_set, 2):
            test_axis = np.cross(s1.coords - s2.coords, axis)
            if np.linalg.norm(test_axis) > self.tol:
                op = SymmOp.from_axis_angle_and_translation(test_axis, 180)
                r2present = self.is_valid_op(op)
                if r2present:
                    self.symmops.append(op)
                    self.rot_sym.append((test_axis, 2))
                    return True


Instruction:
Implement a function in Python 3 to
handle Sperhical Top Molecules.

Response:
def _proc_sph_top(self):
        """
        Handles Sperhical Top Molecules, which belongs to the T, O or I point
        groups.
        """
        self._find_spherical_axes()
        if len(self.rot_sym) == 0:
            logger.debug("Accidental speherical top!")
            self._proc_sym_top()
        main_axis, rot = max(self.rot_sym, key=lambda v: v[1])
        if rot < 3:
            logger.debug("Accidental speherical top!")
            self._proc_sym_top()
        elif rot == 3:
            mirror_type = self._find_mirror(main_axis)
            if mirror_type != "":
                if self.is_valid_op(PointGroupAnalyzer.inversion_op):
                    self.symmops.append(PointGroupAnalyzer.inversion_op)
                    self.sch_symbol = "Th"
                else:
                    self.sch_symbol = "Td"
            else:
                self.sch_symbol = "T"
        elif rot == 4:
            if self.is_valid_op(PointGroupAnalyzer.inversion_op):
                self.symmops.append(PointGroupAnalyzer.inversion_op)
                self.sch_symbol = "Oh"
            else:
                self.sch_symbol = "O"
        elif rot == 5:
            if self.is_valid_op(PointGroupAnalyzer.inversion_op):
                self.symmops.append(PointGroupAnalyzer.inversion_op)
                self.sch_symbol = "Ih"
            else:
                self.sch_symbol = "I"


Instruction:
Create a Python 3 function to
find spherical top molecules.

Response:
def _find_spherical_axes(self):
        """
        Looks for R5, R4, R3 and R2 axes in spherical top molecules.  Point
        group T molecules have only one unique 3-fold and one unique 2-fold
        axis. O molecules have one unique 4, 3 and 2-fold axes. I molecules
        have a unique 5-fold axis.
        """
        rot_present = defaultdict(bool)
        origin_site, dist_el_sites = cluster_sites(self.centered_mol, self.tol)
        test_set = min(dist_el_sites.values(), key=lambda s: len(s))
        coords = [s.coords for s in test_set]
        for c1, c2, c3 in itertools.combinations(coords, 3):
            for cc1, cc2 in itertools.combinations([c1, c2, c3], 2):
                if not rot_present[2]:
                    test_axis = cc1 + cc2
                    if np.linalg.norm(test_axis) > self.tol:
                        op = SymmOp.from_axis_angle_and_translation(test_axis,
                                                                    180)
                        rot_present[2] = self.is_valid_op(op)
                        if rot_present[2]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, 2))

            test_axis = np.cross(c2 - c1, c3 - c1)
            if np.linalg.norm(test_axis) > self.tol:
                for r in (3, 4, 5):
                    if not rot_present[r]:
                        op = SymmOp.from_axis_angle_and_translation(
                            test_axis, 360 / r)
                        rot_present[r] = self.is_valid_op(op)
                        if rot_present[r]:
                            self.symmops.append(op)
                            self.rot_sym.append((test_axis, r))
                            break
            if rot_present[2] and rot_present[3] and (
                        rot_present[4] or rot_present[5]):
                break


Instruction:
Can you implement a function in Python 3 that
checks if a particular symmetry operation is a valid symmetry operation for a molecule.

Response:
def is_valid_op(self, symmop):
        """
        Check if a particular symmetry operation is a valid symmetry operation
        for a molecule, i.e., the operation maps all atoms to another
        equivalent atom.

        Args:
            symmop (SymmOp): Symmetry operation to test.

        Returns:
            (bool): Whether SymmOp is valid for Molecule.
        """
        coords = self.centered_mol.cart_coords
        for site in self.centered_mol:
            coord = symmop.operate(site.coords)
            ind = find_in_coord_list(coords, coord, self.tol)
            if not (len(ind) == 1
                    and self.centered_mol[ind[0]].species
                    == site.species):
                return False
        return True


Instruction:
Write a Python 3 function for
calculating the dictionary of indices mapping equivalent atoms onto each other.

Response:
def _get_eq_sets(self):
        """
        Calculates the dictionary for mapping equivalent atoms onto each other.

        Args:
            None

        Returns:
            dict: The returned dictionary has two possible keys:

            ``eq_sets``:
            A dictionary of indices mapping to sets of indices,
            each key maps to indices of all equivalent atoms.
            The keys are guaranteed to be not equivalent.

            ``sym_ops``:
            Twofold nested dictionary.
            ``operations[i][j]`` gives the symmetry operation
            that maps atom ``i`` unto ``j``.
        """
        UNIT = np.eye(3)
        eq_sets, operations = defaultdict(set), defaultdict(dict)
        symm_ops = [op.rotation_matrix
                    for op in generate_full_symmops(self.symmops, self.tol)]

        def get_clustered_indices():
            indices = cluster_sites(self.centered_mol, self.tol,
                                    give_only_index=True)
            out = list(indices[1].values())
            if indices[0] is not None:
                out.append([indices[0]])
            return out

        for index in get_clustered_indices():
            sites = self.centered_mol.cart_coords[index]
            for i, reference in zip(index, sites):
                for op in symm_ops:
                    rotated = np.dot(op, sites.T).T
                    matched_indices = find_in_coord_list(rotated, reference,
                                                         self.tol)
                    matched_indices = {
                        dict(enumerate(index))[i] for i in matched_indices}
                    eq_sets[i] |= matched_indices

                    if i not in operations:
                        operations[i] = {j: op.T if j != i else UNIT
                                         for j in matched_indices}
                    else:
                        for j in matched_indices:
                            if j not in operations[i]:
                                operations[i][j] = op.T if j != i else UNIT
                    for j in matched_indices:
                        if j not in operations:
                            operations[j] = {i: op if j != i else UNIT}
                        elif i not in operations[j]:
                            operations[j][i] = op if j != i else UNIT

        return {'eq_sets': eq_sets,
                'sym_ops': operations}


Instruction:
Write a Python 3 script to
combine the dicts of _get_equivalent_atom_dicts into one.

Response:
def _combine_eq_sets(eq_sets, operations):
        """Combines the dicts of _get_equivalent_atom_dicts into one

        Args:
            eq_sets (dict)
            operations (dict)

        Returns:
            dict: The returned dictionary has two possible keys:

            ``eq_sets``:
            A dictionary of indices mapping to sets of indices,
            each key maps to indices of all equivalent atoms.
            The keys are guaranteed to be not equivalent.

            ``sym_ops``:
            Twofold nested dictionary.
            ``operations[i][j]`` gives the symmetry operation
            that maps atom ``i`` unto ``j``.
        """
        UNIT = np.eye(3)

        def all_equivalent_atoms_of_i(i, eq_sets, ops):
            """WORKS INPLACE on operations
            """
            visited = set([i])
            tmp_eq_sets = {j: (eq_sets[j] - visited) for j in eq_sets[i]}

            while tmp_eq_sets:
                new_tmp_eq_sets = {}
                for j in tmp_eq_sets:
                    if j in visited:
                        continue
                    visited.add(j)
                    for k in tmp_eq_sets[j]:
                        new_tmp_eq_sets[k] = eq_sets[k] - visited
                        if i not in ops[k]:
                            ops[k][i] = (np.dot(ops[j][i], ops[k][j])
                                         if k != i else UNIT)
                        ops[i][k] = ops[k][i].T
                tmp_eq_sets = new_tmp_eq_sets
            return visited, ops

        eq_sets = copy.deepcopy(eq_sets)
        new_eq_sets = {}
        ops = copy.deepcopy(operations)
        to_be_deleted = set()
        for i in eq_sets:
            if i in to_be_deleted:
                continue
            visited, ops = all_equivalent_atoms_of_i(i, eq_sets, ops)
            to_be_deleted |= visited - {i}

        for k in to_be_deleted:
            eq_sets.pop(k, None)
        return {'eq_sets': eq_sets,
                'sym_ops': ops}


Instruction:
Can you generate a brief explanation for the following Python 3 code
def symmetrize_molecule(self):
        eq = self.get_equivalent_atoms()
        eq_sets, ops = eq['eq_sets'], eq['sym_ops']
        coords = self.centered_mol.cart_coords.copy()
        for i, eq_indices in eq_sets.items():
            for j in eq_indices:
                coords[j] = np.dot(ops[j][i], coords[j])
            coords[i] = np.mean(coords[list(eq_indices)], axis=0)
            for j in eq_indices:
                if j == i:
                    continue
                coords[j] = np.dot(ops[i][j], coords[i])
                coords[j] = np.dot(ops[i][j], coords[i])
        molecule = Molecule(species=self.centered_mol.species_and_occu,
                            coords=coords)
        return {'sym_mol': molecule,
                'eq_sets': eq_sets,
                'sym_ops': ops}

Response: Returns a symmetrized molecule with equivalent atoms obtained via get_equivalent_atoms.


Instruction:
Given the following Python 3 function, write the documentation
def are_symmetrically_equivalent(self, sites1, sites2, symm_prec=1e-3):
        def in_sites(site):
            for test_site in sites1:
                if test_site.is_periodic_image(site, symm_prec, False):
                    return True
            return False

        for op in self:
            newsites2 = [PeriodicSite(site.species,
                                      op.operate(site.frac_coords),
                                      site.lattice) for site in sites2]
            for site in newsites2:
                if not in_sites(site):
                    break
            else:
                return True
        return False

Response: Test if two sets of PeriodicSites are actually symmetrically equivalent under this space group.


Instruction:
Create a Python 3 function for
finding the indices of matches of a particular coord in a coord_list.

Response:
def find_in_coord_list(coord_list, coord, atol=1e-8):
    """
    Find the indices of matches of a particular coord in a coord_list.

    Args:
        coord_list: List of coords to test
        coord: Specific coordinates
        atol: Absolute tolerance. Defaults to 1e-8. Accepts both scalar and
            array.

    Returns:
        Indices of matches, e.g., [0, 1, 2, 3]. Empty list if not found.
    """
    if len(coord_list) == 0:
        return []
    diff = np.array(coord_list) - np.array(coord)[None, :]
    return np.where(np.all(np.abs(diff) < atol, axis=1))[0]


Instruction:
Given the following Python 3 function, write the documentation
def in_coord_list(coord_list, coord, atol=1e-8):
    return len(find_in_coord_list(coord_list, coord, atol=atol)) > 0

Response: Tests if a particular coord is within a coord_list.


Instruction:
Write a Python 3 function that can
test if all coords in subset are contained in superset.

Response:
def is_coord_subset(subset, superset, atol=1e-8):
    """
    Tests if all coords in subset are contained in superset.
    Doesn't use periodic boundary conditions

    Args:
        subset, superset: List of coords

    Returns:
        True if all of subset is in superset.
    """
    c1 = np.array(subset)
    c2 = np.array(superset)
    is_close = np.all(np.abs(c1[:, None, :] - c2[None, :, :]) < atol, axis=-1)
    any_close = np.any(is_close, axis=-1)
    return np.all(any_close)


Instruction:
Given the following Python 3 function, write the documentation
def coord_list_mapping(subset, superset, atol=1e-8):
    c1 = np.array(subset)
    c2 = np.array(superset)
    inds = np.where(np.all(np.isclose(c1[:, None, :], c2[None, :, :], atol=atol),
                           axis=2))[1]
    result = c2[inds]
    if not np.allclose(c1, result, atol=atol):
        if not is_coord_subset(subset, superset):
            raise ValueError("subset is not a subset of superset")
    if not result.shape == c1.shape:
        raise ValueError("Something wrong with the inputs, likely duplicates "
                         "in superset")
    return inds

Response: Gives the index mapping from a subset to a superset.


Instruction:
Make a summary of the following Python 3 code
def coord_list_mapping_pbc(subset, superset, atol=1e-8):
    atol = np.array([1., 1. ,1.]) * atol
    return cuc.coord_list_mapping_pbc(subset, superset, atol)

Response: Returns the index mapping from a subset to a superset.


Instruction:
Explain what the following Python 3 code does
def get_linear_interpolated_value(x_values, y_values, x):
    a = np.array(sorted(zip(x_values, y_values), key=lambda d: d[0]))

    ind = np.where(a[:, 0] >= x)[0]

    if len(ind) == 0 or ind[0] == 0:
        raise ValueError("x is out of range of provided x_values")

    i = ind[0]
    x1, x2 = a[i - 1][0], a[i][0]
    y1, y2 = a[i - 1][1], a[i][1]

    return y1 + (y2 - y1) / (x2 - x1) * (x - x1)

Response: Returns an interpolated value by linear interpolation between two values.


Instruction:
How would you explain what the following Python 3 function does
def all_distances(coords1, coords2):
    c1 = np.array(coords1)
    c2 = np.array(coords2)
    z = (c1[:, None, :] - c2[None, :, :]) ** 2
    return np.sum(z, axis=-1) ** 0.5

Response: Returns the distances between two lists of coordinates coords1 and coords2.


Instruction:
Can you generate the documentation for the following Python 3 function
def pbc_diff(fcoords1, fcoords2):
    fdist = np.subtract(fcoords1, fcoords2)
    return fdist - np.round(fdist)

Response:
Returns the fractional distance between two fractional coordinates taking into
    account periodic boundary conditions.


Instruction:
Write a Python 3 script to
find the indices of all points in a fractional coord list that are equal to a specific fractional coord.

Response:
def find_in_coord_list_pbc(fcoord_list, fcoord, atol=1e-8):
    """
    Get the indices of all points in a fractional coord list that are
    equal to a fractional coord (with a tolerance), taking into account
    periodic boundary conditions.

    Args:
        fcoord_list: List of fractional coords
        fcoord: A specific fractional coord to test.
        atol: Absolute tolerance. Defaults to 1e-8.

    Returns:
        Indices of matches, e.g., [0, 1, 2, 3]. Empty list if not found.
    """
    if len(fcoord_list) == 0:
        return []
    fcoords = np.tile(fcoord, (len(fcoord_list), 1))
    fdist = fcoord_list - fcoords
    fdist -= np.round(fdist)
    return np.where(np.all(np.abs(fdist) < atol, axis=1))[0]


Instruction:
Given the following Python 3 function, write the documentation
def in_coord_list_pbc(fcoord_list, fcoord, atol=1e-8):
    return len(find_in_coord_list_pbc(fcoord_list, fcoord, atol=atol)) > 0

Response: Tests if a particular fractional coord is within a fractional coord_list.


Instruction:
Here you have a function in Python 3, explain what it does
def is_coord_subset_pbc(subset, superset, atol=1e-8, mask=None):
    c1 = np.array(subset, dtype=np.float64)
    c2 = np.array(superset, dtype=np.float64)
    if mask is not None:
        m = np.array(mask, dtype=np.int)
    else:
        m = np.zeros((len(subset), len(superset)), dtype=np.int)
    atol = np.zeros(3, dtype=np.float64) + atol
    return cuc.is_coord_subset_pbc(c1, c2, atol, m)

Response: Tests if all fractional coords in subset are contained in superset.


Instruction:
Can you write a function in Python 3 where it
returns the list of points on the original lattice contained in the supercell in fractional coordinates.

Response:
def lattice_points_in_supercell(supercell_matrix):
    """
    Returns the list of points on the original lattice contained in the
    supercell in fractional coordinates (with the supercell basis).
    e.g. [[2,0,0],[0,1,0],[0,0,1]] returns [[0,0,0],[0.5,0,0]]

    Args:
        supercell_matrix: 3x3 matrix describing the supercell

    Returns:
        numpy array of the fractional coordinates
    """
    diagonals = np.array(
        [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1],
         [1, 1, 0], [1, 1, 1]])
    d_points = np.dot(diagonals, supercell_matrix)

    mins = np.min(d_points, axis=0)
    maxes = np.max(d_points, axis=0) + 1

    ar = np.arange(mins[0], maxes[0])[:, None] * \
         np.array([1, 0, 0])[None, :]
    br = np.arange(mins[1], maxes[1])[:, None] * \
         np.array([0, 1, 0])[None, :]
    cr = np.arange(mins[2], maxes[2])[:, None] * \
         np.array([0, 0, 1])[None, :]

    all_points = ar[:, None, None] + br[None, :, None] + cr[None, None, :]
    all_points = all_points.reshape((-1, 3))

    frac_points = np.dot(all_points, np.linalg.inv(supercell_matrix))

    tvects = frac_points[np.all(frac_points < 1 - 1e-10, axis=1)
                         & np.all(frac_points >= -1e-10, axis=1)]
    assert len(tvects) == round(abs(np.linalg.det(supercell_matrix)))
    return tvects


Instruction:
Here you have a function in Python 3, explain what it does
def barycentric_coords(coords, simplex):
    coords = np.atleast_2d(coords)

    t = np.transpose(simplex[:-1, :]) - np.transpose(simplex[-1, :])[:, None]
    all_but_one = np.transpose(
        np.linalg.solve(t, np.transpose(coords - simplex[-1])))
    last_coord = 1 - np.sum(all_but_one, axis=-1)[:, None]
    return np.append(all_but_one, last_coord, axis=-1)

Response:
Converts a list of coordinates to barycentric coordinates given a
    simplex with d + 1 points. Only works for d > = 2.


Instruction:
Write a Python 3 function for
calculating the angle between two vectors.

Response:
def get_angle(v1, v2, units="degrees"):
    """
    Calculates the angle between two vectors.

    Args:
        v1: Vector 1
        v2: Vector 2
        units: "degrees" or "radians". Defaults to "degrees".

    Returns:
        Angle between them in degrees.
    """
    d = np.dot(v1, v2) / np.linalg.norm(v1) / np.linalg.norm(v2)
    d = min(d, 1)
    d = max(d, -1)
    angle = math.acos(d)
    if units == "degrees":
        return math.degrees(angle)
    elif units == "radians":
        return angle
    else:
        raise ValueError("Invalid units {}".format(units))


Instruction:
How would you code a function in Python 3 to
volume of the simplex.

Response:
def volume(self):
        """
        Volume of the simplex.
        """
        return abs(np.linalg.det(self._aug)) / math.factorial(self.simplex_dim)


Instruction:
Write a Python 3 script for
computing the intersection points of a line with a simplex.

Response:
def line_intersection(self, point1, point2, tolerance=1e-8):
        """
        Computes the intersection points of a line with a simplex
        Args:
            point1, point2 ([float]): Points that determine the line
        Returns:
            points where the line intersects the simplex (0, 1, or 2)
        """
        b1 = self.bary_coords(point1)
        b2 = self.bary_coords(point2)
        l = b1 - b2
        # don't use barycentric dimension where line is parallel to face
        valid = np.abs(l) > 1e-10
        # array of all the barycentric coordinates on the line where
        # one of the values is 0
        possible = b1 - (b1[valid] / l[valid])[:, None] * l
        barys = []
        for p in possible:
            # it's only an intersection if its in the simplex
            if (p >= -tolerance).all():
                found = False
                # don't return duplicate points
                for b in barys:
                    if np.all(np.abs(b - p) < tolerance):
                        found = True
                        break
                if not found:
                    barys.append(p)
        assert len(barys) < 3
        return [self.point_from_bary_coords(b) for b in barys]


Instruction:
Given the following Python 3 function, write the documentation
def is_valid_bibtex(reference):
    # str is necessary since pybtex seems to have an issue with unicode. The
    # filter expression removes all non-ASCII characters.
    sio = StringIO(remove_non_ascii(reference))
    parser = bibtex.Parser()
    errors.set_strict_mode(False)
    bib_data = parser.parse_stream(sio)
    return len(bib_data.entries) > 0

Response: Use pybtex to validate that a reference is in proper BibTeX format.


Instruction:
Explain what the following Python 3 code does
def parse_history_node(h_node):
        if isinstance(h_node, dict):
            return HistoryNode.from_dict(h_node)

        else:
            if len(h_node) != 3:
                raise ValueError("Invalid History node, "
                                 "should be dict or (name, version, "
                                 "description) tuple: {}".format(h_node))
            return HistoryNode(h_node[0], h_node[1], h_node[2])

Response: Parses a History Node object from either a dict or a 3 - element tuple.


Instruction:
Write a Python 3 function that can
parse an Author object from either a String dict or tuple.

Response:
def parse_author(author):
        """
        Parses an Author object from either a String, dict, or tuple

        Args:
            author: A String formatted as "NAME <email@domain.com>",
                (name, email) tuple, or a dict with name and email keys.

        Returns:
            An Author object.
        """
        if isinstance(author, str):
            # Regex looks for whitespace, (any name), whitespace, <, (email),
            # >, whitespace
            m = re.match(r'\s*(.*?)\s*<(.*?@.*?)>\s*', author)
            if not m or m.start() != 0 or m.end() != len(author):
                raise ValueError("Invalid author format! {}".format(author))
            return Author(m.groups()[0], m.groups()[1])
        elif isinstance(author, dict):
            return Author.from_dict(author)
        else:
            if len(author) != 2:
                raise ValueError("Invalid author, should be String or (name, "
                                 "email) tuple: {}".format(author))
            return Author(author[0], author[1])


Instruction:
Given the following Python 3 function, write the documentation
def from_structures(cls, structures, authors, projects=None,
                        references='', remarks=None, data=None,
                        histories=None, created_at=None):
        """
        A convenience method for getting a list of StructureNL objects by
        specifying structures and metadata separately. Some of the metadata
        is applied to all of the structures for ease of use.

        Args:
            structures: A list of Structure objects
            authors: *List* of {"name":'', "email":''} dicts,
                *list* of Strings as 'John Doe <johndoe@gmail.com>',
                or a single String with commas separating authors
            projects: List of Strings ['Project A', 'Project B']. This
                applies to all structures.
            references: A String in BibTeX format. Again, this applies to all
                structures.
            remarks: List of Strings ['Remark A', 'Remark B']
            data: A list of free form dict. Namespaced at the root level
                with an underscore, e.g. {"_materialsproject":<custom data>}
                . The length of data should be the same as the list of
                structures if not None.
            histories: List of list of dicts - [[{'name':'', 'url':'',
                'description':{}}], ...] The length of histories should be the
                same as the list of structures if not None.
            created_at: A datetime object
        """
        data = [{}] * len(structures) if data is None else data
        histories = [[]] * len(structures) if histories is None else \
            histories

        snl_list = []
        for i, struct in enumerate(structures):
            snl = StructureNL(struct, authors, projects=projects,
                              references=references,
                              remarks=remarks, data=data[i],
                              history=histories[i],
                              created_at=created_at)
            snl_list.append(snl)

        return snl_list

Response: This method creates a list of StructureNL objects from a list of structures and metadata.


Instruction:
Here you have a function in Python 3, explain what it does
def get_perturbed_indices(self, tol=1e-8):
        indices = list(zip(*np.where(abs(self - np.eye(3)) > tol)))
        return indices

Response: Gets indices of perturbed elements of the deformation gradient i. e. those that differ from the identity ArcGIS - 2.


Instruction:
Create a Python 3 function to
apply the deformation gradient to a structure.

Response:
def apply_to_structure(self, structure):
        """
        Apply the deformation gradient to a structure.

        Args:
            structure (Structure object): the structure object to
                be modified by the deformation
        """
        def_struct = structure.copy()
        old_latt = def_struct.lattice.matrix
        new_latt = np.transpose(np.dot(self, np.transpose(old_latt)))
        def_struct.lattice = Lattice(new_latt)
        return def_struct


Instruction:
Can you tell what is the following Python 3 function doing
def from_index_amount(cls, matrixpos, amt):
        f = np.identity(3)
        f[matrixpos] += amt
        return cls(f)

Response: Returns a new object from a matrix position and amount


Instruction:
How would you explain what the following Python 3 function does
def from_deformation(cls, deformation):
        dfm = Deformation(deformation)
        return cls(0.5 * (np.dot(dfm.trans, dfm) - np.eye(3)))

Response: Returns a Strain object from a deformation matrix


Instruction:
Create a Python 3 function for
returning a new instance of the class from the index location and amount.

Response:
def from_index_amount(cls, idx, amount):
        """
        Like Deformation.from_index_amount, except generates
        a strain from the zero 3x3 tensor or voigt vector with
        the amount specified in the index location.  Ensures
        symmetric strain.

        Args:
            idx (tuple or integer): index to be perturbed, can be voigt or
                full-tensor notation
            amount (float): amount to perturb selected index
        """
        if np.array(idx).ndim == 0:
            v = np.zeros(6)
            v[idx] = amount
            return cls.from_voigt(v)
        elif np.array(idx).ndim == 1:
            v = np.zeros((3, 3))
            for i in itertools.permutations(idx):
                v[i] = amount
            return cls(v)
        else:
            raise ValueError("Index must either be 2-tuple or integer "
                             "corresponding to full-tensor or voigt index")


Instruction:
Implement a function in Python 3 to
convert a tuple to a string that can be used in the template for the Agrs object.

Response:
def hkl_tuple_to_str(hkl):
    """
    Prepare for display on plots
    "(hkl)" for surfaces
    Agrs:
        hkl: in the form of [h, k, l] or (h, k, l)
    """
    str_format = '($'
    for x in hkl:
        if x < 0:
            str_format += '\\overline{' + str(-x) + '}'
        else:
            str_format += str(x)
    str_format += '$)'
    return str_format


Instruction:
Can you tell what is the following Python 3 function doing
def get_tri_area(pts):
    a, b, c = pts[0], pts[1], pts[2]
    v1 = np.array(b) - np.array(a)
    v2 = np.array(c) - np.array(a)
    area_tri = abs(sp.linalg.norm(sp.cross(v1, v2)) / 2)
    return area_tri

Response: Given a list of coords for 3 points compute the area of this triangle.


Instruction:
Explain what the following Python 3 code does
def _get_all_miller_e(self):
        all_hkl = []
        color_ind = self.color_ind
        planes = []
        recp = self.structure.lattice.reciprocal_lattice_crystallographic
        recp_symmops = get_recp_symmetry_operation(self.structure, self.symprec)

        for i, (hkl, energy) in enumerate(zip(self.hkl_list,
                                              self.e_surf_list)):
            for op in recp_symmops:
                miller = tuple([int(x) for x in op.operate(hkl)])
                if miller not in all_hkl:
                    all_hkl.append(miller)
                    normal = recp.get_cartesian_coords(miller)
                    normal /= sp.linalg.norm(normal)
                    normal_pt = [x * energy for x in normal]
                    dual_pt = [x / energy for x in normal]
                    color_plane = color_ind[divmod(i, len(color_ind))[1]]
                    planes.append(WulffFacet(normal, energy, normal_pt,
                                             dual_pt, color_plane, i, hkl))

        # sort by e_surf
        planes.sort(key=lambda x: x.e_surf)
        return planes

Response: get all the miller in the system


Instruction:
How would you explain what the following Python 3 function does
def _get_cross_pt_dual_simp(self, dual_simp):
        matrix_surfs = [self.facets[dual_simp[i]].normal for i in range(3)]
        matrix_e = [self.facets[dual_simp[i]].e_surf for i in range(3)]
        cross_pt = sp.dot(sp.linalg.inv(matrix_surfs), matrix_e)
        return cross_pt

Response: Get the cross - vector for a dual triangulation of the current set of simplices.


Instruction:
Make a summary of the following Python 3 code
def _get_simpx_plane(self):
        on_wulff = [False] * len(self.miller_list)
        surface_area = [0.0] * len(self.miller_list)
        for simpx in self.wulff_cv_simp:
            pts = [self.wulff_pt_list[simpx[i]] for i in range(3)]
            center = np.sum(pts, 0) / 3.0
            # check whether the center of the simplices is on one plane
            for plane in self.facets:
                abs_diff = abs(np.dot(plane.normal, center) - plane.e_surf)
                if abs_diff < 1e-5:
                    on_wulff[plane.index] = True
                    surface_area[plane.index] += get_tri_area(pts)

                    plane.points.append(pts)
                    plane.outer_lines.append([simpx[0], simpx[1]])
                    plane.outer_lines.append([simpx[1], simpx[2]])
                    plane.outer_lines.append([simpx[0], simpx[2]])
                    # already find the plane, move to the next simplices
                    break
        for plane in self.facets:
            plane.outer_lines.sort()
            plane.outer_lines = [line for line in plane.outer_lines
                                 if plane.outer_lines.count(line) != 2]
        return on_wulff, surface_area

Response: Locate the plane for the simpx of on wulff_cv.


Instruction:
Create a Python 3 function to
get the colors for the current set of on_wulff facets.

Response:
def _get_colors(self, color_set, alpha, off_color, custom_colors={}):
        """
        assign colors according to the surface energies of on_wulff facets.

        return:
            (color_list, color_proxy, color_proxy_on_wulff, miller_on_wulff,
            e_surf_on_wulff_list)
        """
        import matplotlib as mpl
        import matplotlib.pyplot as plt
        color_list = [off_color] * len(self.hkl_list)
        color_proxy_on_wulff = []
        miller_on_wulff = []
        e_surf_on_wulff = [(i, e_surf)
                           for i, e_surf in enumerate(self.e_surf_list)
                           if self.on_wulff[i]]

        c_map = plt.get_cmap(color_set)
        e_surf_on_wulff.sort(key=lambda x: x[1], reverse=False)
        e_surf_on_wulff_list = [x[1] for x in e_surf_on_wulff]
        if len(e_surf_on_wulff) > 1:
            cnorm = mpl.colors.Normalize(vmin=min(e_surf_on_wulff_list),
                                         vmax=max(e_surf_on_wulff_list))
        else:
            # if there is only one hkl on wulff, choose the color of the median
            cnorm = mpl.colors.Normalize(vmin=min(e_surf_on_wulff_list) - 0.1,
                                         vmax=max(e_surf_on_wulff_list) + 0.1)
        scalar_map = mpl.cm.ScalarMappable(norm=cnorm, cmap=c_map)

        for i, e_surf in e_surf_on_wulff:
            color_list[i] = scalar_map.to_rgba(e_surf, alpha=alpha)
            if tuple(self.miller_list[i]) in custom_colors.keys():
                color_list[i] = custom_colors[tuple(self.miller_list[i])]
            color_proxy_on_wulff.append(
                plt.Rectangle((2, 2), 1, 1, fc=color_list[i], alpha=alpha))
            miller_on_wulff.append(self.input_miller_fig[i])
        scalar_map.set_array([x[1] for x in e_surf_on_wulff])
        color_proxy = [plt.Rectangle((2, 2), 1, 1, fc=x, alpha=alpha)
                       for x in color_list]

        return color_list, color_proxy, color_proxy_on_wulff, miller_on_wulff, \
            e_surf_on_wulff_list


Instruction:
Implement a function in Python 3 to
return the sorted pts in a facet used to draw a line in a facet

Response:
def get_line_in_facet(self, facet):
        """
        Returns the sorted pts in a facet used to draw a line
        """

        lines = list(facet.outer_lines)
        pt = []
        prev = None
        while len(lines) > 0:
            if prev is None:
                l = lines.pop(0)
            else:
                for i, l in enumerate(lines):
                    if prev in l:
                        l = lines.pop(i)
                        if l[1] == prev:
                            l.reverse()
                        break
            # make sure the lines are connected one by one.
            # find the way covering all pts and facets
            pt.append(self.wulff_pt_list[l[0]].tolist())
            pt.append(self.wulff_pt_list[l[1]].tolist())
            prev = l[1]

        return pt


Instruction:
How would you implement a function in Python 3 that
returns a matplotlib. pyplot object for the Wulff shape plot.

Response:
def get_plot(self, color_set='PuBu', grid_off=True, axis_off=True,
                 show_area=False, alpha=1, off_color='red', direction=None,
                 bar_pos=(0.75, 0.15, 0.05, 0.65), bar_on=False, units_in_JPERM2=True,
                 legend_on=True, aspect_ratio=(8, 8), custom_colors={}):
        """
        Get the Wulff shape plot.

        Args:
            color_set: default is 'PuBu'
            grid_off (bool): default is True
            axis_off (bool): default is Ture
            show_area (bool): default is False
            alpha (float): chosen from 0 to 1 (float), default is 1
            off_color: Default color for facets not present on the Wulff shape.
            direction: default is (1, 1, 1)
            bar_pos: default is [0.75, 0.15, 0.05, 0.65]
            bar_on (bool): default is False
            legend_on (bool): default is True
            aspect_ratio: default is (8, 8)
            custom_colors ({(h,k,l}: [r,g,b,alpha}): Customize color of each
                facet with a dictionary. The key is the corresponding Miller
                index and value is the color. Undefined facets will use default
                color site. Note: If you decide to set your own colors, it
                probably won't make any sense to have the color bar on.

        Return:
            (matplotlib.pyplot)
        """
        import matplotlib as mpl
        import matplotlib.pyplot as plt
        import mpl_toolkits.mplot3d as mpl3
        color_list, color_proxy, color_proxy_on_wulff, \
            miller_on_wulff, e_surf_on_wulff = self._get_colors(
                color_set, alpha, off_color, custom_colors=custom_colors)

        if not direction:
            # If direction is not specified, use the miller indices of
            # maximum area.
            direction = max(self.area_fraction_dict.items(),
                            key=lambda x: x[1])[0]

        fig = plt.figure()
        fig.set_size_inches(aspect_ratio[0], aspect_ratio[1])
        azim, elev = self._get_azimuth_elev([direction[0], direction[1],
                                             direction[-1]])

        wulff_pt_list = self.wulff_pt_list

        ax = mpl3.Axes3D(fig, azim=azim, elev=elev)

        for plane in self.facets:
            # check whether [pts] is empty
            if len(plane.points) < 1:
                # empty, plane is not on_wulff.
                continue
            # assign the color for on_wulff facets according to its
            # index and the color_list for on_wulff
            plane_color = color_list[plane.index]
            pt = self.get_line_in_facet(plane)
            # plot from the sorted pts from [simpx]
            tri = mpl3.art3d.Poly3DCollection([pt])
            tri.set_color(plane_color)
            tri.set_edgecolor("#808080")
            ax.add_collection3d(tri)

        # set ranges of x, y, z
        # find the largest distance between on_wulff pts and the origin,
        # to ensure complete and consistent display for all directions
        r_range = max([np.linalg.norm(x) for x in wulff_pt_list])
        ax.set_xlim([-r_range * 1.1, r_range * 1.1])
        ax.set_ylim([-r_range * 1.1, r_range * 1.1])
        ax.set_zlim([-r_range * 1.1, r_range * 1.1])
        # add legend
        if legend_on:
            color_proxy = color_proxy
            if show_area:
                ax.legend(color_proxy, self.miller_area, loc='upper left',
                          bbox_to_anchor=(0, 1), fancybox=True, shadow=False)
            else:
                ax.legend(color_proxy_on_wulff, miller_on_wulff,
                          loc='upper center',
                          bbox_to_anchor=(0.5, 1), ncol=3, fancybox=True,
                          shadow=False)
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_zlabel('z')

        # Add colorbar
        if bar_on:
            cmap = plt.get_cmap(color_set)
            cmap.set_over('0.25')
            cmap.set_under('0.75')
            bounds = [round(e, 2) for e in e_surf_on_wulff]
            bounds.append(1.2 * bounds[-1])
            norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
            # display surface energies
            ax1 = fig.add_axes(bar_pos)
            cbar = mpl.colorbar.ColorbarBase(
                ax1, cmap=cmap, norm=norm, boundaries=[0] + bounds + [10],
                extend='both', ticks=bounds[:-1], spacing='proportional',
                orientation='vertical')
            units = "$J/m^2$" if units_in_JPERM2 else "$eV/\AA^2$"
            cbar.set_label('Surface Energies (%s)' %(units), fontsize=100)

        if grid_off:
            ax.grid('off')
        if axis_off:
            ax.axis('off')
        return plt


Instruction:
Can you tell what is the following Python 3 function doing
def _get_azimuth_elev(self, miller_index):
        if miller_index == (0, 0, 1) or miller_index == (0, 0, 0, 1):
            return 0, 90
        else:
            cart = self.lattice.get_cartesian_coords(miller_index)
            azim = get_angle([cart[0], cart[1], 0], (1, 0, 0))
            v = [cart[0], cart[1], 0]
            elev = get_angle(cart, v)
            return azim, elev

Response: Returns the azimuth and elevation of a centric miller in the current species.


Instruction:
Write a Python 3 script to
return a dictionary of area fractions for all the resource classes in the Miller area.

Response:
def area_fraction_dict(self):
        """
        Returns:
            (dict): {hkl: area_hkl/total area on wulff}
        """
        return {hkl: self.miller_area_dict[hkl] / self.surface_area
                for hkl in self.miller_area_dict.keys()}


Instruction:
Implement a function in Python 3 to
return the anisotropy of the resource entry.

Response:
def anisotropy(self):
        """
        Returns:
            (float) Coefficient of Variation from weighted surface energy
            The ideal sphere is 0.
        """
        square_diff_energy = 0
        weighted_energy = self.weighted_surface_energy
        area_frac_dict = self.area_fraction_dict
        miller_energy_dict = self.miller_energy_dict

        for hkl in miller_energy_dict.keys():
            square_diff_energy += (miller_energy_dict[hkl] - weighted_energy)\
                                  ** 2 * area_frac_dict[hkl]
        return np.sqrt(square_diff_energy) / weighted_energy


Instruction:
Write a Python 3 script for
returning the total surface energy of the Wulff shape.

Response:
def total_surface_energy(self):
        """
        Total surface energy of the Wulff shape.

        Returns:
            (float) sum(surface_energy_hkl * area_hkl)
        """
        tot_surface_energy = 0
        for hkl in self.miller_energy_dict.keys():
            tot_surface_energy += self.miller_energy_dict[hkl] * \
                                  self.miller_area_dict[hkl]
        return tot_surface_energy


Instruction:
Write a Python 3 function that can
return the number of edges in the convex hull.

Response:
def tot_edges(self):
        """
        Returns the number of edges in the convex hull.
            Useful for identifying catalytically active sites.
        """
        all_edges = []
        for facet in self.facets:
            edges = []
            pt = self.get_line_in_facet(facet)

            lines = []
            for i, p in enumerate(pt):
                if i == len(pt) / 2:
                    break
                lines.append(tuple(sorted(tuple([tuple(pt[i*2]), tuple(pt[i*2+1])]))))

            for i, p in enumerate(lines):
                if p not in all_edges:
                    edges.append(p)

            all_edges.extend(edges)

        return len(all_edges)


Instruction:
Write a Python 3 script for
constructing a SpaceGroupTransformation from its transformation string.

Response:
def from_transformation_string(cls, transformation_string="a,b,c;0,0,0"):
        """
        Construct SpaceGroupTransformation from its transformation string.
        :param P: matrix
        :param p: origin shift vector
        :return:
        """
        P, p = JonesFaithfulTransformation.parse_transformation_string(
            transformation_string)
        return cls(P, p)


Instruction:
Can you implement a function in Python 3 that
returns the inverse of the system

Response:
def inverse(self):
        # type: () -> JonesFaithfulTransformation
        """

        :return: JonesFaithfulTransformation
        """
        Q = np.linalg.inv(self.P)
        return JonesFaithfulTransformation(Q, -np.matmul(Q, self.p))


Instruction:
Implement a Python 3 function for
taking a symmetry operation and transforms it.

Response:
def transform_symmop(self, symmop):
        # type: (Union[SymmOp, MagSymmOp]) -> Union[SymmOp, MagSymmOp]
        """
        Takes a symmetry operation and transforms it.
        :param symmop: SymmOp or MagSymmOp
        :return:
        """
        W = symmop.rotation_matrix
        w = symmop.translation_vector
        Q = np.linalg.inv(self.P)
        W_ = np.matmul(np.matmul(Q, W), self.P)
        I = np.identity(3)
        w_ = np.matmul(Q, (w + np.matmul(W - I, self.p)))
        if isinstance(symmop, MagSymmOp):
            return MagSymmOp.from_rotation_and_translation_and_time_reversal(
                rotation_matrix=W_, translation_vec=w_,
                time_reversal=symmop.time_reversal, tol=symmop.tol)
        elif isinstance(symmop, SymmOp):
            return SymmOp.from_rotation_and_translation(
                rotation_matrix=W_, translation_vec=w_, tol=symmop.tol)


Instruction:
Here you have a function in Python 3, explain what it does
def transform_coords(self, coords):
        # type: (List[List[float]]) -> List[List[float]]
        """
        Takes a list of co-ordinates and transforms them.
        :param coords: List of coords
        :return:
        """
        new_coords = []
        for x in coords:
            x = np.array(x)
            Q = np.linalg.inv(self.P)
            x_ = np.matmul(Q, (x - self.p))
            new_coords.append(x_.tolist())
        return new_coords

Response: Takes a list of co -ordinates and transforms them.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def transform_lattice(self, lattice):
        # type: (Lattice) -> Lattice
        """
        Takes a Lattice object and transforms it.
        :param lattice: Lattice
        :return:
        """
        return Lattice(np.matmul(lattice.matrix, self.P))

Response: Takes a Lattice object and transforms it.


Instruction:
Here you have a function in Python 3, explain what it does
def _find_codopant(target, oxidation_state, allowed_elements=None):
    ref_radius = target.ionic_radius
    candidates = []
    symbols = allowed_elements or [el.symbol for el in Element]
    for sym in symbols:
        try:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                sp = Specie(sym, oxidation_state)
                r = sp.ionic_radius
                if r is not None:
                    candidates.append((r, sp))
        except:
            pass
    return min(candidates, key=lambda l: abs(l[0] / ref_radius - 1))[1]

Response: Find the element from the allowed elements that possesses the desired oxidation state and returns the closest in ionic radius to the target.


Instruction:
How would you code a function in Python 3 to
apply the transformation to the structure.

Response:
def apply_transformation(self, structure, return_ranked_list=False):
        """
        Return either a single ordered structure or a sequence of all ordered
        structures.

        Args:
            structure: Structure to order.
            return_ranked_list (bool): Whether or not multiple structures are
                returned. If return_ranked_list is a number, that number of
                structures is returned.

        Returns:
            Depending on returned_ranked list, either a transformed structure
            or a list of dictionaries, where each dictionary is of the form
            {"structure" = .... , "other_arguments"}

            The list of ordered structures is ranked by ewald energy / atom, if
            the input structure is an oxidation state decorated structure.
            Otherwise, it is ranked by number of sites, with smallest number of
            sites first.
        """
        try:
            num_to_return = int(return_ranked_list)
        except ValueError:
            num_to_return = 1

        if self.refine_structure:
            finder = SpacegroupAnalyzer(structure, self.symm_prec)
            structure = finder.get_refined_structure()

        contains_oxidation_state = all(
            [hasattr(sp, "oxi_state") and sp.oxi_state != 0 for sp in
             structure.composition.elements]
        )

        structures = None

        if structure.is_ordered:
            warn("Enumeration skipped for structure with composition {} "
                 "because it is ordered".format(structure.composition))
            structures = [structure.copy()]

        if self.max_disordered_sites:
            ndisordered = sum([1 for site in structure if not site.is_ordered])
            if ndisordered > self.max_disordered_sites:
                raise ValueError(
                    "Too many disordered sites! ({} > {})".format(
                        ndisordered, self.max_disordered_sites))
            max_cell_sizes = range(self.min_cell_size, int(
                math.floor(self.max_disordered_sites / ndisordered)) + 1)
        else:
            max_cell_sizes = [self.max_cell_size]

        for max_cell_size in max_cell_sizes:
            adaptor = EnumlibAdaptor(
                structure, min_cell_size=self.min_cell_size,
                max_cell_size=max_cell_size,
                symm_prec=self.symm_prec, refine_structure=False,
                enum_precision_parameter=self.enum_precision_parameter,
                check_ordered_symmetry=self.check_ordered_symmetry,
                timeout=self.timeout)
            try:
                adaptor.run()
            except EnumError:
                warn("Unable to enumerate for max_cell_size = %d".format(
                    max_cell_size))
            structures = adaptor.structures
            if structures:
                break

        if structures is None:
            raise ValueError("Unable to enumerate")

        original_latt = structure.lattice
        inv_latt = np.linalg.inv(original_latt.matrix)
        ewald_matrices = {}
        all_structures = []
        for s in structures:
            new_latt = s.lattice
            transformation = np.dot(new_latt.matrix, inv_latt)
            transformation = tuple([tuple([int(round(cell)) for cell in row])
                                    for row in transformation])
            if contains_oxidation_state and self.sort_criteria == "ewald":
                if transformation not in ewald_matrices:
                    s_supercell = structure * transformation
                    ewald = EwaldSummation(s_supercell)
                    ewald_matrices[transformation] = ewald
                else:
                    ewald = ewald_matrices[transformation]
                energy = ewald.compute_sub_structure(s)
                all_structures.append({"num_sites": len(s), "energy": energy,
                                       "structure": s})
            else:
                all_structures.append({"num_sites": len(s), "structure": s})

        def sort_func(s):
            return s["energy"] / s["num_sites"] \
                if contains_oxidation_state and self.sort_criteria == "ewald" \
                else s["num_sites"]

        self._all_structures = sorted(all_structures, key=sort_func)

        if return_ranked_list:
            return self._all_structures[0:num_to_return]
        else:
            return self._all_structures[0]["structure"]


Instruction:
Can you implement a function in Python 3 that
checks if a periodic site satisfies the constraint.

Response:
def satisfies_constraint(self, site):
        """
        Checks if a periodic site satisfies the constraint.
        """
        if not site.is_ordered:
            return False

        if self.species_constraints \
                and str(site.specie) in self.species_constraints:
            satisfies_constraints = True
        else:
            satisfies_constraints = False

        if self.site_constraint_name \
                and self.site_constraint_name in site.properties:
            prop = site.properties[self.site_constraint_name]
            if prop in self.site_constraints:
                satisfies_constraints = True
            else:
                satisfies_constraints = False

        return satisfies_constraints


Instruction:
Can you tell what is the following Python 3 function doing
def determine_min_cell(disordered_structure):

        def lcm(n1, n2):
            """
            Find least common multiple of two numbers
            """
            return n1 * n2 / gcd(n1, n2)

        # assumes all order parameters for a given species are the same
        mag_species_order_parameter = {}
        mag_species_occurrences = {}
        for idx, site in enumerate(disordered_structure):
            if not site.is_ordered:
                op = max(site.species.values())
                # this very hacky bit of code only works because we know
                # that on disordered sites in this class, all species are the same
                # but have different spins, and this is comma-delimited
                sp = str(list(site.species.keys())[0]).split(",")[0]
                if sp in mag_species_order_parameter:
                    mag_species_occurrences[sp] += 1
                else:
                    mag_species_order_parameter[sp] = op
                    mag_species_occurrences[sp] = 1

        smallest_n = []

        for sp, order_parameter in mag_species_order_parameter.items():
            denom = Fraction(order_parameter).limit_denominator(100).denominator
            num_atom_per_specie = mag_species_occurrences[sp]
            n_gcd = gcd(denom, num_atom_per_specie)
            smallest_n.append(lcm(int(n_gcd), denom) / n_gcd)

        return max(smallest_n)

Response: Determines the smallest supercell that is able to enumerate the given structure with the given order parameter.


Instruction:
Explain what the following Python 3 code does
def _remove_dummy_species(structure):
        if not structure.is_ordered:
            raise Exception("Something went wrong with enumeration.")

        sites_to_remove = []
        logger.debug('Dummy species structure:\n{}'.format(str(structure)))
        for idx, site in enumerate(structure):
            if isinstance(site.specie, DummySpecie):
                sites_to_remove.append(idx)
                spin = site.specie._properties.get('spin', None)
                neighbors = structure.get_neighbors(
                    site,
                    0.05,  # arbitrary threshold, needs to be << any bond length
                    # but >> floating point precision issues
                    include_index=True
                )
                if len(neighbors) != 1:
                    raise Exception("This shouldn't happen, found neighbors: {}"
                                    .format(neighbors))
                orig_site_idx = neighbors[0][2]
                orig_specie = structure[orig_site_idx].specie
                new_specie = Specie(orig_specie.symbol,
                                    getattr(orig_specie, 'oxi_state', None),
                                    properties={'spin': spin})
                structure.replace(orig_site_idx,
                                  new_specie,
                                  properties=structure[orig_site_idx].properties)
        structure.remove_sites(sites_to_remove)
        logger.debug('Structure with dummy species removed:\n{}'.format(str(structure)))
        return structure

Response: Removes dummy species from a structure. Used after performing enumeration.


Instruction:
Implement a function in Python 3 to
replace Spin. up and Spin. down with spin magnitudes specified by mag_species_spin.

Response:
def _add_spin_magnitudes(self, structure):
        """
        Replaces Spin.up/Spin.down with spin magnitudes specified
        by mag_species_spin.
        :param structure:
        :return:
        """
        for idx, site in enumerate(structure):
            if getattr(site.specie, '_properties', None):
                spin = site.specie._properties.get('spin', None)
                sign = int(spin) if spin else 0
                if spin:
                    new_properties = site.specie._properties.copy()
                    # this very hacky bit of code only works because we know
                    # that on disordered sites in this class, all species are the same
                    # but have different spins, and this is comma-delimited
                    sp = str(site.specie).split(",")[0]
                    new_properties.update({
                        'spin': sign * self.mag_species_spin.get(sp, 0)
                    })
                    new_specie = Specie(site.specie.symbol,
                                        getattr(site.specie, 'oxi_state', None),
                                        new_properties)
                    structure.replace(idx, new_specie,
                                      properties=site.properties)
        logger.debug('Structure with spin magnitudes:\n{}'.format(str(structure)))
        return structure


Instruction:
Can you implement a function in Python 3 that
applies the transformation to an input structure.

Response:
def apply_transformation(self, structure, return_ranked_list=False):
        """
        Apply MagOrderTransformation to an input structure.
        :param structure: Any ordered structure.
        :param return_ranked_list: As in other Transformations.
        :return:
        """

        if not structure.is_ordered:
            raise ValueError("Create an ordered approximation of "
                             "your  input structure first.")

        # retrieve order parameters
        order_parameters = [MagOrderParameterConstraint.from_dict(op_dict)
                            for op_dict in self.order_parameter]
        # add dummy species on which to perform enumeration
        structure = self._add_dummy_species(structure, order_parameters)

        # trivial case
        if structure.is_ordered:
            structure = self._remove_dummy_species(structure)
            return [structure] if return_ranked_list > 1 else structure

        enum_kwargs = self.enum_kwargs.copy()

        enum_kwargs["min_cell_size"] = max(
            int(self.determine_min_cell(structure)),
            enum_kwargs.get("min_cell_size", 1)
        )

        if enum_kwargs.get("max_cell_size", None):
            if enum_kwargs["min_cell_size"] > enum_kwargs["max_cell_size"]:
                warnings.warn("Specified max cell size ({}) is smaller "
                              "than the minimum enumerable cell size ({}), "
                              "changing max cell size to {}".format(enum_kwargs["max_cell_size"],
                                                                    enum_kwargs["min_cell_size"],
                                                                    enum_kwargs["min_cell_size"]))
                enum_kwargs["max_cell_size"] = enum_kwargs["min_cell_size"]
        else:
            enum_kwargs["max_cell_size"] = enum_kwargs["min_cell_size"]

        t = EnumerateStructureTransformation(**enum_kwargs)

        alls = t.apply_transformation(structure,
                                      return_ranked_list=return_ranked_list)

        # handle the fact that EnumerateStructureTransformation can either
        # return a single Structure or a list
        if isinstance(alls, Structure):
            # remove dummy species and replace Spin.up or Spin.down
            # with spin magnitudes given in mag_species_spin arg
            alls = self._remove_dummy_species(alls)
            alls = self._add_spin_magnitudes(alls)
        else:
            for idx, _ in enumerate(alls):
                alls[idx]["structure"] = self._remove_dummy_species(alls[idx]["structure"])
                alls[idx]["structure"] = self._add_spin_magnitudes(alls[idx]["structure"])

        try:
            num_to_return = int(return_ranked_list)
        except ValueError:
            num_to_return = 1

        if num_to_return == 1 or not return_ranked_list:
            return alls[0]["structure"] if num_to_return else alls

        # remove duplicate structures and group according to energy model
        m = StructureMatcher(comparator=SpinComparator())
        key = lambda x: SpacegroupAnalyzer(x, 0.1).get_space_group_number()
        out = []
        for _, g in groupby(sorted([d["structure"] for d in alls],
                                   key=key), key):
            g = list(g)
            grouped = m.group_structures(g)
            out.extend([{"structure": g[0],
                         "energy": self.energy_model.get_energy(g[0])}
                        for g in grouped])

        self._all_structures = sorted(out, key=lambda d: d["energy"])

        return self._all_structures[0:num_to_return]


Instruction:
Can you tell what is the following Python 3 function doing
def apply_transformation(self, structure, return_ranked_list=False):
        comp = structure.composition
        logger.info("Composition: %s" % comp)

        for sp in comp:
            try:
                sp.oxi_state
            except AttributeError:
                analyzer = BVAnalyzer()
                structure = analyzer.get_oxi_state_decorated_structure(
                    structure)
                comp = structure.composition
                break

        ox = self.dopant.oxi_state
        radius = self.dopant.ionic_radius

        compatible_species = [
            sp for sp in comp if sp.oxi_state == ox and
            abs(sp.ionic_radius / radius - 1) < self.ionic_radius_tol]

        if (not compatible_species) and self.alio_tol:
            # We only consider aliovalent doping if there are no compatible
            # isovalent species.
            compatible_species = [
                sp for sp in comp
                if abs(sp.oxi_state - ox) <= self.alio_tol and
                abs(sp.ionic_radius / radius - 1) < self.ionic_radius_tol and
                sp.oxi_state * ox >= 0]

        if self.allowed_doping_species is not None:
            # Only keep allowed doping species.
            compatible_species = [
                sp for sp in compatible_species
                if sp in [get_el_sp(s) for s in self.allowed_doping_species]]

        logger.info("Compatible species: %s" % compatible_species)

        lengths = structure.lattice.abc
        scaling = [max(1, int(round(math.ceil(self.min_length / x))))
                   for x in lengths]
        logger.info("Lengths are %s" % str(lengths))
        logger.info("Scaling = %s" % str(scaling))

        all_structures = []
        t = EnumerateStructureTransformation(**self.kwargs)

        for sp in compatible_species:
            supercell = structure * scaling
            nsp = supercell.composition[sp]
            if sp.oxi_state == ox:
                supercell.replace_species({sp: {sp: (nsp - 1) / nsp,
                                                self.dopant: 1 / nsp}})
                logger.info("Doping %s for %s at level %.3f" % (
                    sp, self.dopant, 1 / nsp))
            elif self.codopant:
                codopant = _find_codopant(sp, 2 * sp.oxi_state - ox)
                supercell.replace_species({sp: {sp: (nsp - 2) / nsp,
                                                self.dopant: 1 / nsp,
                                                codopant: 1 / nsp}})
                logger.info("Doping %s for %s + %s at level %.3f" % (
                    sp, self.dopant, codopant, 1 / nsp))
            elif abs(sp.oxi_state) < abs(ox):
                # Strategy: replace the target species with a
                # combination of dopant and vacancy.
                # We will choose the lowest oxidation state species as a
                # vacancy compensation species as it is likely to be lower in
                # energy
                sp_to_remove = min([s for s in comp if s.oxi_state * ox > 0],
                                   key=lambda ss: abs(ss.oxi_state))

                if sp_to_remove == sp:
                    common_charge = lcm(int(abs(sp.oxi_state)), int(abs(ox)))
                    ndopant = common_charge / abs(ox)
                    nsp_to_remove = common_charge / abs(sp.oxi_state)
                    logger.info("Doping %d %s with %d %s." %
                                (nsp_to_remove, sp, ndopant, self.dopant))
                    supercell.replace_species(
                        {sp: {sp: (nsp - nsp_to_remove) / nsp,
                              self.dopant: ndopant / nsp}})
                else:
                    ox_diff = int(abs(round(sp.oxi_state - ox)))
                    vac_ox = int(abs(sp_to_remove.oxi_state))
                    common_charge = lcm(vac_ox, ox_diff)
                    ndopant = common_charge / ox_diff
                    nx_to_remove = common_charge / vac_ox
                    nx = supercell.composition[sp_to_remove]
                    logger.info("Doping %d %s with %s and removing %d %s." %
                                (ndopant, sp, self.dopant,
                                 nx_to_remove, sp_to_remove))
                    supercell.replace_species(
                        {sp: {sp: (nsp - ndopant) / nsp,
                              self.dopant: ndopant / nsp},
                         sp_to_remove: {
                             sp_to_remove: (nx - nx_to_remove) / nx}})
            elif abs(sp.oxi_state) > abs(ox):
                # Strategy: replace the target species with dopant and also
                # remove some opposite charged species for charge neutrality
                if ox > 0:
                    sp_to_remove = max(supercell.composition.keys(),
                                       key=lambda el: el.X)
                else:
                    sp_to_remove = min(supercell.composition.keys(),
                                       key=lambda el: el.X)
                # Confirm species are of opposite oxidation states.
                assert sp_to_remove.oxi_state * sp.oxi_state < 0

                ox_diff = int(abs(round(sp.oxi_state - ox)))
                anion_ox = int(abs(sp_to_remove.oxi_state))
                nx = supercell.composition[sp_to_remove]
                common_charge = lcm(anion_ox, ox_diff)
                ndopant = common_charge / ox_diff
                nx_to_remove = common_charge / anion_ox
                logger.info("Doping %d %s with %s and removing %d %s." %
                            (ndopant, sp, self.dopant,
                             nx_to_remove, sp_to_remove))
                supercell.replace_species(
                    {sp: {sp: (nsp - ndopant) / nsp,
                          self.dopant: ndopant / nsp},
                     sp_to_remove: {sp_to_remove: (nx - nx_to_remove) / nx}})

            ss = t.apply_transformation(
                supercell, return_ranked_list=self.max_structures_per_enum)
            logger.info("%s distinct structures" % len(ss))
            all_structures.extend(ss)

        logger.info("Total %s doped structures" % len(all_structures))
        if return_ranked_list:
            return all_structures[:return_ranked_list]

        return all_structures[0]["structure"]

Response: Applies the transformation to a structure.


Instruction:
Given the following Python 3 function, write the documentation
def apply_transformation(self, structure, return_ranked_list=False):

        if not structure.is_ordered:
            raise ValueError("This transformation is for disordered structures only.")

        partitions = self._partition_species(structure.composition,
                                             max_components=self.max_sites_to_merge)
        disorder_mappings = self._get_disorder_mappings(structure.composition, partitions)

        disordered_structures = []
        for mapping in disorder_mappings:
            disordered_structure = structure.copy()
            disordered_structure.replace_species(mapping)
            disordered_structures.append({'structure': disordered_structure,
                                          'mapping': mapping})

        if len(disordered_structures) == 0:
            return None
        elif not return_ranked_list:
            return disordered_structures[0]['structure']
        else:
            if len(disordered_structures) > return_ranked_list:
                disordered_structures = disordered_structures[0:return_ranked_list]
            return disordered_structures

Response: Applies the transformation to a single structure.


Instruction:
Here you have a function in Python 3, explain what it does
def read_grid_from_file(filename):
    try:
        f = open(filename, mode='r')
        full_res = ast.literal_eval(f.read())
        f.close()
    except SyntaxError:
        print('Problems reading ', filename)
        full_res = {'grid': 0, 'all_done': False}
    except (OSError, IOError):
        full_res = {'grid': 0, 'all_done': False}
    return full_res

Response: Read the results of a full set of calculations from a file.


Instruction:
Explain what the following Python 3 code does
def pred_from_structures(self, target_species, structures_list,
                             remove_duplicates=True, remove_existing=False):
        """
        performs a structure prediction targeting compounds containing all of
        the target_species, based on a list of structure (those structures
        can for instance come from a database like the ICSD). It will return
        all the structures formed by ionic substitutions with a probability
        higher than the threshold

        Notes:
        If the default probability model is used, input structures must
        be oxidation state decorated. See AutoOxiStateDecorationTransformation

        This method does not change the number of species in a structure. i.e
        if the number of target species is 3, only input structures containing
        3 species will be considered.

        Args:
            target_species:
                a list of species with oxidation states
                e.g., [Specie('Li',1),Specie('Ni',2), Specie('O',-2)]

            structures_list:
                a list of dictionnary of the form {'structure':Structure object
                ,'id':some id where it comes from}
                the id can for instance refer to an ICSD id.

            remove_duplicates:
                if True, the duplicates in the predicted structures will
                be removed

            remove_existing:
                if True, the predicted structures that already exist in the
                structures_list will be removed

        Returns:
            a list of TransformedStructure objects.
        """
        target_species = get_el_sp(target_species)
        result = []
        transmuter = StandardTransmuter([])
        if len(list(set(target_species) & set(self.get_allowed_species()))) \
                != len(target_species):
            raise ValueError("the species in target_species are not allowed "
                             + "for the probability model you are using")

        for permut in itertools.permutations(target_species):
            for s in structures_list:
                # check if: species are in the domain,
                # and the probability of subst. is above the threshold
                els = s['structure'].composition.elements
                if len(els) == len(permut) and \
                                len(list(set(els) & set(
                                    self.get_allowed_species()))) == \
                                len(els) and self._sp.cond_prob_list(permut,
                                                                     els) > \
                        self._threshold:

                    clean_subst = {els[i]: permut[i]
                                   for i in range(0, len(els))
                                   if els[i] != permut[i]}

                    if len(clean_subst) == 0:
                        continue

                    transf = SubstitutionTransformation(clean_subst)

                    if Substitutor._is_charge_balanced(
                            transf.apply_transformation(s['structure'])):
                        ts = TransformedStructure(
                            s['structure'], [transf],
                            history=[{"source": s['id']}],
                            other_parameters={
                                'type': 'structure_prediction',
                                'proba': self._sp.cond_prob_list(permut, els)}
                        )
                        result.append(ts)
                        transmuter.append_transformed_structures([ts])

        if remove_duplicates:
            transmuter.apply_filter(RemoveDuplicatesFilter(
                symprec=self._symprec))
        if remove_existing:
            # Make the list of structures from structures_list that corresponds to the
            # target species
            chemsys = list(set([sp.symbol for sp in target_species]))
            structures_list_target = [st['structure'] for st in structures_list
                                      if Substitutor._is_from_chemical_system(
                    chemsys,
                    st['structure'])]
            transmuter.apply_filter(RemoveExistingFilter(structures_list_target,
                                                         symprec=self._symprec))
        return transmuter.transformed_structures

Response: This method performs a structure prediction targeting compounds containing all of the target_species and returns a list of TransformedStructure objects.


Instruction:
Write a Python 3 function for
checking if the structure object is charge balanced

Response:
def _is_charge_balanced(struct):
        """
        checks if the structure object is charge balanced
        """
        if sum([s.specie.oxi_state for s in struct.sites]) == 0.0:
            return True
        else:
            return False


Instruction:
Can you tell what is the following Python 3 function doing
def _is_from_chemical_system(chemical_system, struct):
        chemsys = list(set([sp.symbol for sp in struct.composition]))
        if len(chemsys) != len(chemical_system):
            return False
        for el in chemsys:
            if not el in chemical_system:
                return False
        return True

Response: Checks if the structure object is from the given chemical system


Instruction:
Make a summary of the following Python 3 code
def pred_from_list(self, species_list):
        species_list = get_el_sp(species_list)
        # calculate the highest probabilities to help us stop the recursion
        max_probabilities = []
        for s2 in species_list:
            max_p = 0
            for s1 in self._sp.species:
                max_p = max([self._sp.cond_prob(s1, s2), max_p])
            max_probabilities.append(max_p)
        output = []

        def _recurse(output_prob, output_species):
            best_case_prob = list(max_probabilities)
            best_case_prob[:len(output_prob)] = output_prob
            if functools.reduce(mul, best_case_prob) > self._threshold:
                if len(output_species) == len(species_list):
                    odict = {
                        'substitutions':
                            dict(zip(species_list, output_species)),
                        'probability': functools.reduce(mul, best_case_prob)}
                    output.append(odict)
                    return
                for sp in self._sp.species:
                    i = len(output_prob)
                    prob = self._sp.cond_prob(sp, species_list[i])
                    _recurse(output_prob + [prob], output_species + [sp])

        _recurse([], [])
        logging.info('{} substitutions found'.format(len(output)))
        return output

Response: Given a list of species and a probability value return a list of dictionaries each including a substitutions dictionary and a probability value.


Instruction:
Make a summary of the following Python 3 code
def pred_from_comp(self, composition):
        output = []
        predictions = self.pred_from_list(composition.elements)
        for p in predictions:
            subs = p['substitutions']
            charge = 0
            for i_el in composition.elements:
                f_el = subs[i_el]
                charge += f_el.oxi_state * composition[i_el]
            if charge == 0:
                output.append(p)
        logging.info('{} charge balanced '
                     'compositions found'.format(len(output)))
        return output

Response: Returns a list of dicts representing the set of compositions that are charge balanced.


Instruction:
Can you generate the documentation for the following Python 3 function
def pretty_plot(width=8, height=None, plt=None, dpi=None,
                color_cycle=("qualitative", "Set1_9")):
    """
    Provides a publication quality plot, with nice defaults for font sizes etc.

    Args:
        width (float): Width of plot in inches. Defaults to 8in.
        height (float): Height of plot in inches. Defaults to width * golden
            ratio.
        plt (matplotlib.pyplot): If plt is supplied, changes will be made to an
            existing plot. Otherwise, a new plot will be created.
        dpi (int): Sets dot per inch for figure. Defaults to 300.
        color_cycle (tuple): Set the color cycle for new plots to one of the
            color sets in palettable. Defaults to a qualitative Set1_9.

    Returns:
        Matplotlib plot object with properly sized fonts.
    """
    ticksize = int(width * 2.5)

    golden_ratio = (math.sqrt(5) - 1) / 2

    if not height:
        height = int(width * golden_ratio)

    if plt is None:
        import matplotlib.pyplot as plt
        import importlib
        mod = importlib.import_module("palettable.colorbrewer.%s" %
                                      color_cycle[0])
        colors = getattr(mod, color_cycle[1]).mpl_colors
        from cycler import cycler

        plt.figure(figsize=(width, height), facecolor="w", dpi=dpi)
        ax = plt.gca()
        ax.set_prop_cycle(cycler('color', colors))
    else:
        fig = plt.gcf()
        fig.set_size_inches(width, height)
    plt.xticks(fontsize=ticksize)
    plt.yticks(fontsize=ticksize)

    ax = plt.gca()
    ax.set_title(ax.get_title(), size=width * 4)

    labelsize = int(width * 3)

    ax.set_xlabel(ax.get_xlabel(), size=labelsize)
    ax.set_ylabel(ax.get_ylabel(), size=labelsize)

    return plt

Response: Returns a matplotlib. pyplot object with properly sized fonts.


Instruction:
Given the following Python 3 function, write the documentation
def pretty_plot_two_axis(x, y1, y2, xlabel=None, y1label=None, y2label=None,
                         width=8, height=None, dpi=300):
    """
    Variant of pretty_plot that does a dual axis plot. Adapted from matplotlib
    examples. Makes it easier to create plots with different axes.

    Args:
        x (np.ndarray/list): Data for x-axis.
        y1 (dict/np.ndarray/list): Data for y1 axis (left). If a dict, it will
            be interpreted as a {label: sequence}.
        y2 (dict/np.ndarray/list): Data for y2 axis (right). If a dict, it will
            be interpreted as a {label: sequence}.
        xlabel (str): If not None, this will be the label for the x-axis.
        y1label (str): If not None, this will be the label for the y1-axis.
        y2label (str): If not None, this will be the label for the y2-axis.
        width (float): Width of plot in inches. Defaults to 8in.
        height (float): Height of plot in inches. Defaults to width * golden
            ratio.
        dpi (int): Sets dot per inch for figure. Defaults to 300.

    Returns:
        matplotlib.pyplot
    """

    import palettable.colorbrewer.diverging

    colors = palettable.colorbrewer.diverging.RdYlBu_4.mpl_colors
    c1 = colors[0]
    c2 = colors[-1]

    golden_ratio = (math.sqrt(5) - 1) / 2

    if not height:
        height = int(width * golden_ratio)

    import matplotlib.pyplot as plt
    width = 12
    labelsize = int(width * 3)
    ticksize = int(width * 2.5)
    styles = ["-", "--", "-.", "."]

    fig, ax1 = plt.subplots()
    fig.set_size_inches((width, height))
    if dpi:
        fig.set_dpi(dpi)
    if isinstance(y1, dict):
        for i, (k, v) in enumerate(y1.items()):
            ax1.plot(x, v, c=c1, marker='s', ls=styles[i % len(styles)],
                     label=k)
        ax1.legend(fontsize=labelsize)
    else:
        ax1.plot(x, y1, c=c1, marker='s', ls='-')

    if xlabel:
        ax1.set_xlabel(xlabel, fontsize=labelsize)

    if y1label:
        # Make the y-axis label, ticks and tick labels match the line color.
        ax1.set_ylabel(y1label, color=c1, fontsize=labelsize)

    ax1.tick_params('x', labelsize=ticksize)
    ax1.tick_params('y', colors=c1, labelsize=ticksize)

    ax2 = ax1.twinx()
    if isinstance(y2, dict):
        for i, (k, v) in enumerate(y2.items()):
            ax2.plot(x, v, c=c2, marker='o', ls=styles[i % len(styles)],
                     label=k)
        ax2.legend(fontsize=labelsize)
    else:
        ax2.plot(x, y2, c=c2, marker='o', ls='-')

    if y2label:
        # Make the y-axis label, ticks and tick labels match the line color.
        ax2.set_ylabel(y2label, color=c2, fontsize=labelsize)

    ax2.tick_params('y', colors=c2, labelsize=ticksize)
    return plt

Response: Pretty plot of two - axis data.


Instruction:
How would you code a function in Python 3 to
return a matplotlib. pyplot object that will plot data based on polynomial fit.

Response:
def pretty_polyfit_plot(x, y, deg=1, xlabel=None, ylabel=None, **kwargs):
    """
    Convenience method to plot data with trend lines based on polynomial fit.

    Args:
        x: Sequence of x data.
        y: Sequence of y data.
        deg (int): Degree of polynomial. Defaults to 1.
        xlabel (str): Label for x-axis.
        ylabel (str): Label for y-axis.
        \\*\\*kwargs: Keyword args passed to pretty_plot.

    Returns:
        matplotlib.pyplot object.
    """
    plt = pretty_plot(**kwargs)
    pp = np.polyfit(x, y, deg)
    xp = np.linspace(min(x), max(x), 200)
    plt.plot(xp, np.polyval(pp, xp), 'k--', x, y, 'o')
    if xlabel:
        plt.xlabel(xlabel)
    if ylabel:
        plt.ylabel(ylabel)
    return plt


Instruction:
Create a Python 3 function to
convert str of chemical formula into latex format for labelling purposes

Response:
def format_formula(formula):
    """
    Converts str of chemical formula into
    latex format for labelling purposes

    Args:
        formula (str): Chemical formula
    """

    formatted_formula = ""
    number_format = ""
    for i, s in enumerate(formula):
        if s.isdigit():
            if not number_format:
                number_format = "_{"
            number_format += s
            if i == len(formula) - 1:
                number_format += "}"
                formatted_formula += number_format
        else:
            if number_format:
                number_format += "}"
                formatted_formula += number_format
                number_format = ""
            formatted_formula += s

    return r"$%s$" % (formatted_formula)


Instruction:
Given the following Python 3 function, write the documentation
def van_arkel_triangle(list_of_materials, annotate=True):

    # F-Fr has the largest X difference. We set this
    # as our top corner of the triangle (most ionic)
    pt1 = np.array([(Element("F").X + Element("Fr").X) / 2,
                    abs(Element("F").X - Element("Fr").X)])
    # Cs-Fr has the lowest average X. We set this as our
    # bottom left corner of the triangle (most metallic)
    pt2 = np.array([(Element("Cs").X + Element("Fr").X) / 2,
                    abs(Element("Cs").X - Element("Fr").X)])
    # O-F has the highest average X. We set this as our
    # bottom right corner of the triangle (most covalent)
    pt3 = np.array([(Element("O").X + Element("F").X) / 2,
                    abs(Element("O").X - Element("F").X)])

    # get the parameters for the lines of the triangle
    d = np.array(pt1) - np.array(pt2)
    slope1 = d[1] / d[0]
    b1 = pt1[1] - slope1 * pt1[0]
    d = pt3 - pt1
    slope2 = d[1] / d[0]
    b2 = pt3[1] - slope2 * pt3[0]

    # Initialize the plt object
    import matplotlib.pyplot as plt

    # set labels and appropriate limits for plot
    plt.xlim(pt2[0] - 0.45, -b2 / slope2 + 0.45)
    plt.ylim(-0.45, pt1[1] + 0.45)
    plt.annotate("Ionic", xy=[pt1[0] - 0.3, pt1[1] + 0.05], fontsize=20)
    plt.annotate("Covalent", xy=[-b2 / slope2 - 0.65, -0.4], fontsize=20)
    plt.annotate("Metallic", xy=[pt2[0] - 0.4, -0.4], fontsize=20)
    plt.xlabel(r"$\frac{\chi_{A}+\chi_{B}}{2}$", fontsize=25)
    plt.ylabel(r"$|\chi_{A}-\chi_{B}|$", fontsize=25)

    # Set the lines of the triangle
    chi_list = [el.X for el in Element]
    plt.plot([min(chi_list), pt1[0]], [slope1 * min(chi_list) + b1, pt1[1]], 'k-', linewidth=3)
    plt.plot([pt1[0], -b2 / slope2], [pt1[1], 0], 'k-', linewidth=3)
    plt.plot([min(chi_list), -b2 / slope2], [0, 0], 'k-', linewidth=3)
    plt.xticks(fontsize=15)
    plt.yticks(fontsize=15)

    # Shade with appropriate colors corresponding to ionic, metallci and covalent
    ax = plt.gca()
    # ionic filling
    ax.fill_between([min(chi_list), pt1[0]],
                    [slope1 * min(chi_list) + b1, pt1[1]], facecolor=[1, 1, 0],
                    zorder=-5, edgecolor=[1, 1, 0])
    ax.fill_between([pt1[0], -b2 / slope2],
                    [pt1[1], slope2 * min(chi_list) - b1], facecolor=[1, 1, 0],
                    zorder=-5, edgecolor=[1, 1, 0])
    # metal filling
    XPt = Element("Pt").X
    ax.fill_between([min(chi_list), (XPt + min(chi_list)) / 2],
                    [0, slope1 * (XPt + min(chi_list)) / 2 + b1],
                    facecolor=[1, 0, 0], zorder=-3, alpha=0.8)
    ax.fill_between([(XPt + min(chi_list)) / 2, XPt],
                    [slope1 * ((XPt + min(chi_list)) / 2) + b1, 0],
                    facecolor=[1, 0, 0], zorder=-3, alpha=0.8)
    # covalent filling
    ax.fill_between([(XPt + min(chi_list)) / 2, ((XPt + min(chi_list)) / 2 + -b2 / slope2) / 2],
                    [0, slope2 * (((XPt + min(chi_list)) / 2 + -b2 / slope2) / 2) + b2],
                    facecolor=[0, 1, 0], zorder=-4, alpha=0.8)
    ax.fill_between([((XPt + min(chi_list)) / 2 + -b2 / slope2) / 2, -b2 / slope2],
                    [slope2 * (((XPt + min(chi_list)) / 2 + -b2 / slope2) / 2) + b2, 0],
                    facecolor=[0, 1, 0], zorder=-4, alpha=0.8)

    # Label the triangle with datapoints
    for entry in list_of_materials:
        if type(entry).__name__ not in ['ComputedEntry', 'ComputedStructureEntry']:
            X_pair = [Element(el).X for el in entry]
            formatted_formula = "%s-%s" % tuple(entry)
        else:
            X_pair = [Element(el).X for el in entry.composition.as_dict().keys()]
            formatted_formula = format_formula(entry.composition.reduced_formula)
        plt.scatter(np.mean(X_pair), abs(X_pair[0] - X_pair[1]), c='b', s=100)
        if annotate:
            plt.annotate(formatted_formula, fontsize=15,
                         xy=[np.mean(X_pair) + 0.005, abs(X_pair[0] - X_pair[1])])

    plt.tight_layout()
    return plt

Response:
This method generates a binary van Arkel - Ketelaar triangle to generate a single compound
           .


Instruction:
Can you tell what is the following Python 3 function doing
def add_fig_kwargs(func):
    from functools import wraps

    @wraps(func)
    def wrapper(*args, **kwargs):
        # pop the kwds used by the decorator.
        title = kwargs.pop("title", None)
        size_kwargs = kwargs.pop("size_kwargs", None)
        show = kwargs.pop("show", True)
        savefig = kwargs.pop("savefig", None)
        tight_layout = kwargs.pop("tight_layout", False)
        ax_grid = kwargs.pop("ax_grid", None)
        ax_annotate = kwargs.pop("ax_annotate", None)

        # Call func and return immediately if None is returned.
        fig = func(*args, **kwargs)
        if fig is None:
            return fig

        # Operate on matplotlib figure.
        if title is not None:
            fig.suptitle(title)

        if size_kwargs is not None:
            fig.set_size_inches(size_kwargs.pop("w"), size_kwargs.pop("h"),
                                **size_kwargs)

        if ax_grid is not None:
            for ax in fig.axes:
                ax.grid(bool(ax_grid))

        if ax_annotate:
            from string import ascii_letters
            tags = ascii_letters
            if len(fig.axes) > len(tags):
                tags = (1 + len(ascii_letters) // len(fig.axes)) * ascii_letters
            for ax, tag in zip(fig.axes, tags):
                ax.annotate("(%s)" % tag, xy=(0.05, 0.95), xycoords="axes fraction")

        if tight_layout:
            try:
                fig.tight_layout()
            except Exception as exc:
                # For some unknown reason, this problem shows up only on travis.
                # https://stackoverflow.com/questions/22708888/valueerror-when-using-matplotlib-tight-layout
                print("Ignoring Exception raised by fig.tight_layout\n", str(exc))

        if savefig:
            fig.savefig(savefig)

        if show:
            import matplotlib.pyplot as plt
            plt.show()

        return fig

    # Add docstring to the decorated method.
    s = "\n\n" + """\
        Keyword arguments controlling the display of the figure:

        ================  ====================================================
        kwargs            Meaning
        ================  ====================================================
        title             Title of the plot (Default: None).
        show              True to show the figure (default: True).
        savefig           "abc.png" or "abc.eps" to save the figure to a file.
        size_kwargs       Dictionary with options passed to fig.set_size_inches
                          e.g. size_kwargs=dict(w=3, h=4)
        tight_layout      True to call fig.tight_layout (default: False)
        ax_grid           True (False) to add (remove) grid from all axes in fig.
                          Default: None i.e. fig is left unchanged.
        ax_annotate       Add labels to  subplots e.g. (a), (b).
                          Default: False
        ================  ====================================================

"""

    if wrapper.__doc__ is not None:
        # Add s at the end of the docstring.
        wrapper.__doc__ += "\n" + s
    else:
        # Use s
        wrapper.__doc__ = s

    return wrapper

Response: Decorator that adds keyword arguments for functions returning matplotlib.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def f0(E, fermi, T):
    return 1. / (1. + np.exp((E - fermi) / (_cd("Boltzmann constant in eV/K") * T)))

Response: Returns the equilibrium fermi - dirac.


Instruction:
Explain what the following Python 3 code does
def _get_orb_type_lobster(orb):
    orb_labs = ["s", "p_y", "p_z", "p_x", "d_xy", "d_yz", "d_z^2",
                "d_xz", "d_x^2-y^2", "f_y(3x^2-y^2)", "f_xyz",
                "f_yz^2", "f_z^3", "f_xz^2", "f_z(x^2-y^2)", "f_x(x^2-3y^2)"]

    try:
        orbital = Orbital(orb_labs.index(orb[1:]))
        return orbital.orbital_type
    except AttributeError:
        print("Orb not in list")

Response: Returns the OrbitalType of the orbital in the lobster.


Instruction:
Make a summary of the following Python 3 code
def _get_orb_lobster(orb):
    orb_labs = ["s", "p_y", "p_z", "p_x", "d_xy", "d_yz", "d_z^2",
                "d_xz", "d_x^2-y^2", "f_y(3x^2-y^2)", "f_xyz",
                "f_yz^2", "f_z^3", "f_xz^2", "f_z(x^2-y^2)", "f_x(x^2-3y^2)"]

    try:
        orbital = Orbital(orb_labs.index(orb[1:]))
        return orbital
    except AttributeError:
        print("Orb not in list")

Response: Returns the Orbital object for the given Orbital object


Instruction:
How would you explain what the following Python 3 function does
def get_interpolated_gap(self, tol=0.001, abs_tol=False, spin=None):

        tdos = self.y if len(self.ydim) == 1 else np.sum(self.y, axis=1)
        if not abs_tol:
            tol = tol * tdos.sum() / tdos.shape[0]
        energies = self.x
        below_fermi = [i for i in range(len(energies))
                       if energies[i] < self.efermi and tdos[i] > tol]
        above_fermi = [i for i in range(len(energies))
                       if energies[i] > self.efermi and tdos[i] > tol]
        vbm_start = max(below_fermi)
        cbm_start = min(above_fermi)
        if vbm_start == cbm_start:
            return 0.0, self.efermi, self.efermi
        else:
            # Interpolate between adjacent values
            terminal_dens = tdos[vbm_start:vbm_start + 2][::-1]
            terminal_energies = energies[vbm_start:vbm_start + 2][::-1]
            start = get_linear_interpolated_value(terminal_dens,
                                                  terminal_energies, tol)
            terminal_dens = tdos[cbm_start - 1:cbm_start + 1]
            terminal_energies = energies[cbm_start - 1:cbm_start + 1]
            end = get_linear_interpolated_value(terminal_dens,
                                                terminal_energies, tol)
            return end - start, end, start

Response: Returns the interpolated gap in the DOS object and the BMM and BMM.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_cbm_vbm(self, tol=0.001, abs_tol=False, spin=None):
        # determine tolerance
        if spin is None:
            tdos = self.y if len(self.ydim) == 1 else np.sum(self.y, axis=1)
        elif spin == Spin.up:
            tdos = self.y[:, 0]
        else:
            tdos = self.y[:, 1]

        if not abs_tol:
            tol = tol * tdos.sum() / tdos.shape[0]

        # find index of fermi energy
        i_fermi = 0
        while self.x[i_fermi] <= self.efermi:
            i_fermi += 1

        # work backwards until tolerance is reached
        i_gap_start = i_fermi
        while i_gap_start - 1 >= 0 and tdos[i_gap_start - 1] <= tol:
            i_gap_start -= 1

        # work forwards until tolerance is reached
        i_gap_end = i_gap_start
        while i_gap_end < tdos.shape[0] and tdos[i_gap_end] <= tol:
            i_gap_end += 1
        i_gap_end -= 1
        return self.x[i_gap_end], self.x[i_gap_start]

Response: Returns the cbm and vbm of the entry in the DOS object.