Instruction:
Explain what the following Python 3 code does
def allocate(self, workdir=None, use_smartio=False):
        if workdir is not None:
            # We set the workdir of the flow here
            self.set_workdir(workdir)
            for i, work in enumerate(self):
                work.set_workdir(os.path.join(self.workdir, "w" + str(i)))

        if not hasattr(self, "workdir"):
            raise RuntimeError("You must call flow.allocate(workdir) if the workdir is not passed to __init__")

        for work in self:
            # Each work has a reference to its flow.
            work.allocate(manager=self.manager)
            work.set_flow(self)
            # Each task has a reference to its work.
            for task in work:
                task.set_work(work)

        self.check_dependencies()

        if not hasattr(self, "_allocated"): self._allocated = 0
        self._allocated += 1

        if use_smartio:
            self.use_smartio()

        return self

Response: Allocate the Flow i. e. assign the workdir and the TaskManager to the different tasks in the Flow.


Instruction:
Write a Python 3 script to
print to the given stream the ASCII representation of the dependency tree.

Response:
def show_dependencies(self, stream=sys.stdout):
        """Writes to the given stream the ASCII representation of the dependency tree."""
        def child_iter(node):
            return [d.node for d in node.deps]

        def text_str(node):
            return colored(str(node), color=node.status.color_opts["color"])

        for task in self.iflat_tasks():
            print(draw_tree(task, child_iter, text_str), file=stream)


Instruction:
Can you generate the documentation for the following Python 3 function
def finalize(self):
        if self.finalized:
            self.history.warning("Calling finalize on an already finalized flow.")
            return 1

        self.history.info("Calling flow.finalize.")
        self.finalized = True

        if self.has_db:
            self.history.info("Saving results in database.")
            try:
                self.flow.db_insert()
                self.finalized = True
            except Exception:
                 logger.critical("MongoDb insertion failed.")
                 return 2

        # Here we remove the big output files if we have the garbage collector
        # and the policy is set to "flow."
        if self.gc is not None and self.gc.policy == "flow":
            self.history.info("gc.policy set to flow. Will clean task output files.")
            for task in self.iflat_tasks():
                task.clean_output_files()

        return 0

Response: This method is called when the flow is complete.


Instruction:
Make a summary of the following Python 3 code
def set_garbage_collector(self, exts=None, policy="task"):
        assert policy in ("task", "flow")
        exts = list_strings(exts) if exts is not None else ("WFK", "SUS", "SCR", "BSR", "BSC")

        gc = GarbageCollector(exts=set(exts), policy=policy)

        self.set_gc(gc)
        for work in self:
            #work.set_gc(gc) # TODO Add support for Works and flow policy
            for task in work:
                task.set_gc(gc)

Response: Enable the garbage collector that will remove the big output files that are not needed.


Instruction:
How would you code a function in Python 3 to
connect the signals within the Flow and the callbacks.

Response:
def connect_signals(self):
        """
        Connect the signals within the `Flow`.
        The `Flow` is responsible for catching the important signals raised from its works.
        """
        # Connect the signals inside each Work.
        for work in self:
            work.connect_signals()

        # Observe the nodes that must reach S_OK in order to call the callbacks.
        for cbk in self._callbacks:
            #cbk.enable()
            for dep in cbk.deps:
                logger.info("connecting %s \nwith sender %s, signal %s" % (str(cbk), dep.node, dep.node.S_OK))
                dispatcher.connect(self.on_dep_ok, signal=dep.node.S_OK, sender=dep.node, weak=False)


Instruction:
Write a Python 3 function for
disabling the signals within the Flow.

Response:
def disconnect_signals(self):
        """Disable the signals within the `Flow`."""
        # Disconnect the signals inside each Work.
        for work in self:
            work.disconnect_signals()

        # Disable callbacks.
        for cbk in self._callbacks:
            cbk.disable()


Instruction:
Can you tell what is the following Python 3 function doing
def set_spectator_mode(self, mode=True):
        # Set the flags of all the nodes in the flow.
        mode = bool(mode)
        self.in_spectator_mode = mode
        for node in self.iflat_nodes():
            node.in_spectator_mode = mode

        # connect/disconnect signals depending on mode.
        if not mode:
            self.connect_signals()
        else:
            self.disconnect_signals()

Response: Set the flow in spectator mode.


Instruction:
Can you implement a function in Python 3 that
uses PyLauncher to submits tasks in rapidfire mode.

Response:
def rapidfire(self, check_status=True, max_nlaunch=-1, max_loops=1, sleep_time=5, **kwargs):
        """
        Use :class:`PyLauncher` to submits tasks in rapidfire mode.
        kwargs contains the options passed to the launcher.

        Args:
            check_status:
            max_nlaunch: Maximum number of launches. default: no limit.
            max_loops: Maximum number of loops
            sleep_time: seconds to sleep between rapidfire loop iterations

        Return:
            Number of tasks submitted.
        """
        self.check_pid_file()
        self.set_spectator_mode(False)
        if check_status: self.check_status()
        from .launcher import PyLauncher
        return PyLauncher(self, **kwargs).rapidfire(max_nlaunch=max_nlaunch, max_loops=max_loops, sleep_time=sleep_time)


Instruction:
Implement a Python 3 function for
using PyLauncher to submit one task.

Response:
def single_shot(self, check_status=True, **kwargs):
        """
        Use :class:`PyLauncher` to submits one task.
        kwargs contains the options passed to the launcher.

        Return:
            number of tasks submitted.
        """
        self.check_pid_file()
        self.set_spectator_mode(False)
        if check_status: self.check_status()
        from .launcher import PyLauncher
        return PyLauncher(self, **kwargs).single_shot()


Instruction:
Can you implement a function in Python 3 that
builds a return a PyFlowScheduler to run the flow.

Response:
def make_scheduler(self, **kwargs):
        """
        Build a return a :class:`PyFlowScheduler` to run the flow.

        Args:
            kwargs: if empty we use the user configuration file.
                    if `filepath` in kwargs we init the scheduler from filepath.
                    else pass **kwargs to :class:`PyFlowScheduler` __init__ method.
        """
        from .launcher import PyFlowScheduler
        if not kwargs:
            # User config if kwargs is empty
            sched = PyFlowScheduler.from_user_config()
        else:
            # Use from_file if filepath if present, else call __init__
            filepath = kwargs.pop("filepath", None)
            if filepath is not None:
                assert not kwargs
                sched = PyFlowScheduler.from_file(filepath)
            else:
                sched = PyFlowScheduler(**kwargs)

        sched.add_flow(self)
        return sched


Instruction:
Implement a Python 3 function for
running the flow in batch mode returns exit status of the job script.

Response:
def batch(self, timelimit=None):
        """
        Run the flow in batch mode, return exit status of the job script.
        Requires a manager.yml file and a batch_adapter adapter.

        Args:
            timelimit: Time limit (int with seconds or string with time given with the slurm convention:
            "days-hours:minutes:seconds"). If timelimit is None, the default value specified in the
            `batch_adapter` entry of `manager.yml` is used.
        """
        from .launcher import BatchLauncher
        # Create a batch dir from the flow.workdir.
        prev_dir = os.path.join(*self.workdir.split(os.path.sep)[:-1])
        prev_dir = os.path.join(os.path.sep, prev_dir)
        workdir = os.path.join(prev_dir, os.path.basename(self.workdir) + "_batch")

        return BatchLauncher(workdir=workdir, flows=self).submit(timelimit=timelimit)


Instruction:
Make a summary of the following Python 3 code
def make_light_tarfile(self, name=None):
        name = os.path.basename(self.workdir) + "-light.tar.gz" if name is None else name
        return self.make_tarfile(name=name, exclude_dirs=["outdata", "indata", "tmpdata"])

Response: Lightweight tarball file. Mainly used for debugging. Return the name of the tarball file.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def make_tarfile(self, name=None, max_filesize=None, exclude_exts=None, exclude_dirs=None, verbose=0, **kwargs):
        def any2bytes(s):
            """Convert string or number to memory in bytes."""
            if is_string(s):
                return int(Memory.from_string(s).to("b"))
            else:
                return int(s)

        if max_filesize is not None:
            max_filesize = any2bytes(max_filesize)

        if exclude_exts:
            # Add/remove ".nc" so that we can simply pass "GSR" instead of "GSR.nc"
            # Moreover this trick allows one to treat WFK.nc and WFK file on the same footing.
            exts = []
            for e in list_strings(exclude_exts):
                exts.append(e)
                if e.endswith(".nc"):
                    exts.append(e.replace(".nc", ""))
                else:
                    exts.append(e + ".nc")
            exclude_exts = exts

        def filter(tarinfo):
            """
            Function that takes a TarInfo object argument and returns the changed TarInfo object.
            If it instead returns None the TarInfo object will be excluded from the archive.
            """
            # Skip links.
            if tarinfo.issym() or tarinfo.islnk():
                if verbose: print("Excluding link: %s" % tarinfo.name)
                return None

            # Check size in bytes
            if max_filesize is not None and tarinfo.size > max_filesize:
                if verbose: print("Excluding %s due to max_filesize" % tarinfo.name)
                return None

            # Filter filenames.
            if exclude_exts and any(tarinfo.name.endswith(ext) for ext in exclude_exts):
                if verbose: print("Excluding %s due to extension" % tarinfo.name)
                return None

            # Exlude directories (use dir basenames).
            if exclude_dirs and any(dir_name in exclude_dirs for dir_name in tarinfo.name.split(os.path.sep)):
                if verbose: print("Excluding %s due to exclude_dirs" % tarinfo.name)
                return None

            return tarinfo

        back = os.getcwd()
        os.chdir(os.path.join(self.workdir, ".."))

        import tarfile
        name = os.path.basename(self.workdir) + ".tar.gz" if name is None else name
        with tarfile.open(name=name, mode='w:gz', **kwargs) as tar:
            tar.add(os.path.basename(self.workdir), arcname=None, recursive=True, exclude=None, filter=filter)

            # Add the script used to generate the flow.
            if self.pyfile is not None and os.path.exists(self.pyfile):
                tar.add(self.pyfile)

        os.chdir(back)
        return name

Response: Create a tarball file from a TarFile object.


Instruction:
Can you tell what is the following Python 3 function doing
def get_graphviz(self, engine="automatic", graph_attr=None, node_attr=None, edge_attr=None):
        self.allocate()

        from graphviz import Digraph
        fg = Digraph("flow", #filename="flow_%s.gv" % os.path.basename(self.relworkdir),
            engine="fdp" if engine == "automatic" else engine)

        # Set graph attributes.
        # https://www.graphviz.org/doc/info/
        #fg.attr(label="%s@%s" % (self.__class__.__name__, self.relworkdir))
        fg.attr(label=repr(self))
        #fg.attr(fontcolor="white", bgcolor='purple:pink')
        fg.attr(rankdir="LR", pagedir="BL")
        #fg.attr(constraint="false", pack="true", packMode="clust")
        fg.node_attr.update(color='lightblue2', style='filled')
        #fg.node_attr.update(ranksep='equally')

        # Add input attributes.
        if graph_attr is not None:
            fg.graph_attr.update(**graph_attr)
        if node_attr is not None:
            fg.node_attr.update(**node_attr)
        if edge_attr is not None:
            fg.edge_attr.update(**edge_attr)

        def node_kwargs(node):
            return dict(
                #shape="circle",
                color=node.color_hex,
                fontsize="8.0",
                label=(str(node) if not hasattr(node, "pos_str") else
                    node.pos_str + "\n" + node.__class__.__name__),
            )

        edge_kwargs = dict(arrowType="vee", style="solid")
        cluster_kwargs = dict(rankdir="LR", pagedir="BL", style="rounded", bgcolor="azure2")

        for work in self:
            # Build cluster with tasks.
            cluster_name = "cluster%s" % work.name
            with fg.subgraph(name=cluster_name) as wg:
                wg.attr(**cluster_kwargs)
                wg.attr(label="%s (%s)" % (work.__class__.__name__, work.name))
                #wg.attr(label=repr(work))
                #wg.attr(label="%s (%s)\n%s (%s)" % (
                #    work.__class__.__name__, work.name, work.relworkdir, work.node_id))
                for task in work:
                    wg.node(task.name, **node_kwargs(task))
                    # Connect children to task.
                    for child in task.get_children():
                        # Find file extensions required by this task
                        i = [dep.node for dep in child.deps].index(task)
                        edge_label = "+".join(child.deps[i].exts)
                        fg.edge(task.name, child.name, label=edge_label, color=task.color_hex,
                                **edge_kwargs)

        # Treat the case in which we have a work producing output for other tasks.
        for work in self:
            children = work.get_children()
            if not children: continue
            cluster_name = "cluster%s" % work.name
            seen = set()
            for child in children:
                # This is not needed, too much confusing
                #fg.edge(cluster_name, child.name, color=work.color_hex, **edge_kwargs)
                # Find file extensions required by work
                i = [dep.node for dep in child.deps].index(work)
                for ext in child.deps[i].exts:
                    out = "%s (%s)" % (ext, work.name)
                    fg.node(out)
                    fg.edge(out, child.name, **edge_kwargs)
                    key = (cluster_name, out)
                    if key not in seen:
                        seen.add(key)
                        fg.edge(cluster_name, out, color=work.color_hex, **edge_kwargs)

        # Treat the case in which we have a task that depends on external files.
        seen = set()
        for task in self.iflat_tasks():
            #print(task.get_parents())
            for node in (p for p in task.get_parents() if p.is_file):
                #print("parent file node", node)
                #infile = "%s (%s)" % (ext, work.name)
                infile = node.filepath
                if infile not in seen:
                    seen.add(infile)
                    fg.node(infile, **node_kwargs(node))

                fg.edge(infile, task.name, color=node.color_hex, **edge_kwargs)

        return fg

Response: Generate a flow in the DOT language.


Instruction:
How would you explain what the following Python 3 function does
def graphviz_imshow(self, ax=None, figsize=None, dpi=300, fmt="png", **kwargs):
        graph = self.get_graphviz(**kwargs)
        graph.format = fmt
        graph.attr(dpi=str(dpi))
        #print(graph)
        _, tmpname = tempfile.mkstemp()
        path = graph.render(tmpname, view=False, cleanup=True)
        ax, fig, _ = get_ax_fig_plt(ax=ax, figsize=figsize, dpi=dpi)
        import matplotlib.image as mpimg
        ax.imshow(mpimg.imread(path, format="png")) #, interpolation="none")
        ax.axis("off")

        return fig

Response: Generate flow graph in the DOT language and plot it with matplotlib.


Instruction:
Write a Python 3 function for
plotting the flow with the connections among the nodes and the status of the tasks.

Response:
def plot_networkx(self, mode="network", with_edge_labels=False, ax=None, arrows=False,
                      node_size="num_cores", node_label="name_class", layout_type="spring", **kwargs):
        """
        Use networkx to draw the flow with the connections among the nodes and
        the status of the tasks.

        Args:
            mode: `networkx` to show connections, `status` to group tasks by status.
            with_edge_labels: True to draw edge labels.
            ax: matplotlib :class:`Axes` or None if a new figure should be created.
            arrows: if True draw arrowheads.
            node_size: By default, the size of the node is proportional to the number of cores used.
            node_label: By default, the task class is used to label node.
            layout_type: Get positions for all nodes using `layout_type`. e.g. pos = nx.spring_layout(g)

        .. warning::

            Requires networkx package.
        """
        self.allocate()

        # Build the graph
        import networkx as nx
        g = nx.Graph() if not arrows else nx.DiGraph()
        edge_labels = {}
        for task in self.iflat_tasks():
            g.add_node(task, name=task.name)
            for child in task.get_children():
                g.add_edge(task, child)
                # TODO: Add getters! What about locked nodes!
                i = [dep.node for dep in child.deps].index(task)
                edge_labels[(task, child)] = " ".join(child.deps[i].exts)

            filedeps = [d for d in task.deps if d.node.is_file]
            for d in filedeps:
                #print(d.node, d.exts)
                g.add_node(d.node, name="%s (%s)" % (d.node.basename, d.node.node_id))
                g.add_edge(d.node, task)
                edge_labels[(d.node, task)] = "+".join(d.exts)

        # This part is needed if we have a work that produces output used by other nodes.
        for work in self:
            children = work.get_children()
            if not children:
                continue
            g.add_node(work, name=work.name)
            for task in work:
                g.add_edge(task, work)
                edge_labels[(task, work)] = "all_ok "
            for child in children:
                #print(child)
                g.add_edge(work, child)
                i = [dep.node for dep in child.deps].index(work)
                edge_labels[(work, child)] = "+".join(child.deps[i].exts)

        # Get positions for all nodes using layout_type.
        # e.g. pos = nx.spring_layout(g)
        pos = getattr(nx, layout_type + "_layout")(g)

        # Select function used to compute the size of the node
        def make_node_size(node):
            if node.is_task:
                return 300 * node.manager.num_cores
            else:
                return 600

        # Function used to build the label
        def make_node_label(node):
            if node_label == "name_class":
                if node.is_file:
                    return "%s\n(%s)" % (node.basename, node.node_id)
                else:
                    return (node.pos_str + "\n" + node.__class__.__name__
                            if hasattr(node, "pos_str") else str(node))
            else:
                raise NotImplementedError("node_label: %s" % str(node_label))

        labels = {node: make_node_label(node) for node in g.nodes()}
        ax, fig, plt = get_ax_fig_plt(ax=ax)

        # Select plot type.
        if mode == "network":
            nx.draw_networkx(g, pos, labels=labels,
                             node_color=[node.color_rgb for node in g.nodes()],
                             node_size=[make_node_size(node) for node in g.nodes()],
                             width=1, style="dotted", with_labels=True, arrows=arrows, ax=ax)

            # Draw edge labels
            if with_edge_labels:
                nx.draw_networkx_edge_labels(g, pos, edge_labels=edge_labels, ax=ax)

        elif mode == "status":
            # Group tasks by status (only tasks are show here).
            for status in self.ALL_STATUS:
                tasks = list(self.iflat_tasks(status=status))

                # Draw nodes (color is given by status)
                node_color = status.color_opts["color"]
                if node_color is None: node_color = "black"
                #print("num nodes %s with node_color %s" % (len(tasks), node_color))

                nx.draw_networkx_nodes(g, pos,
                                       nodelist=tasks,
                                       node_color=node_color,
                                       node_size=[make_node_size(task) for task in tasks],
                                       alpha=0.5, ax=ax
                                       #label=str(status),
                                       )
            # Draw edges.
            nx.draw_networkx_edges(g, pos, width=2.0, alpha=0.5, arrows=arrows, ax=ax) # edge_color='r')

            # Draw labels
            nx.draw_networkx_labels(g, pos, labels, font_size=12, ax=ax)

            # Draw edge labels
            if with_edge_labels:
                nx.draw_networkx_edge_labels(g, pos, edge_labels=edge_labels, ax=ax)
                #label_pos=0.5, font_size=10, font_color='k', font_family='sans-serif', font_weight='normal',
                # alpha=1.0, bbox=None, ax=None, rotate=True, **kwds)

        else:
            raise ValueError("Unknown value for mode: %s" % str(mode))

        ax.axis("off")
        return fig


Instruction:
How would you explain what the following Python 3 function does
def can_execute(self):
        return not self._disabled and all(dep.status == dep.node.S_OK for dep in self.deps)

Response: True if we can execute the callback.


Instruction:
Write a Python 3 script to
create a PhononFlow object from an AbinitInput object defining a ground - state run.

Response:
def from_scf_input(cls, workdir, scf_input, ph_ngqpt, with_becs=True, manager=None, allocate=True):
        """
        Create a `PhononFlow` for phonon calculations from an `AbinitInput` defining a ground-state run.

        Args:
            workdir: Working directory of the flow.
            scf_input: :class:`AbinitInput` object with the parameters for the GS-SCF run.
            ph_ngqpt: q-mesh for phonons. Must be a sub-mesh of the k-mesh used for
                electrons. e.g if ngkpt = (8, 8, 8). ph_ngqpt = (4, 4, 4) is a valid choice
                whereas ph_ngqpt = (3, 3, 3) is not!
            with_becs: True if Born effective charges are wanted.
            manager: :class:`TaskManager` object. Read from `manager.yml` if None.
            allocate: True if the flow should be allocated before returning.

        Return:
            :class:`PhononFlow` object.
        """
        flow = cls(workdir, manager=manager)

        # Register the SCF task
        flow.register_scf_task(scf_input)
        scf_task = flow[0][0]

        # Make sure k-mesh and q-mesh are compatible.
        scf_ngkpt, ph_ngqpt = np.array(scf_input["ngkpt"]), np.array(ph_ngqpt)

        if any(scf_ngkpt % ph_ngqpt != 0):
            raise ValueError("ph_ngqpt %s should be a sub-mesh of scf_ngkpt %s" % (ph_ngqpt, scf_ngkpt))

        # Get the q-points in the IBZ from Abinit
        qpoints = scf_input.abiget_ibz(ngkpt=ph_ngqpt, shiftk=(0, 0, 0), kptopt=1).points

        # Create a PhononWork for each q-point. Add DDK and E-field if q == Gamma and with_becs.
        for qpt in qpoints:
            if np.allclose(qpt, 0) and with_becs:
                ph_work = BecWork.from_scf_task(scf_task)
            else:
                ph_work = PhononWork.from_scf_task(scf_task, qpoints=qpt)

            flow.register_work(ph_work)

        if allocate: flow.allocate()

        return flow


Instruction:
Explain what the following Python 3 code does
def open_final_ddb(self):
        ddb_path = self.outdir.has_abiext("DDB")
        if not ddb_path:
            if self.status == self.S_OK:
                logger.critical("%s reached S_OK but didn't produce a GSR file in %s" % (self, self.outdir))
            return None

        from abipy.dfpt.ddb import DdbFile
        try:
            return DdbFile(ddb_path)
        except Exception as exc:
            logger.critical("Exception while reading DDB file at %s:\n%s" % (ddb_path, str(exc)))
            return None

Response: Open the final DDB file.


Instruction:
Can you tell what is the following Python 3 function doing
def finalize(self):
        # Merge all the out_DDB files found in work.outdir.
        ddb_files = list(filter(None, [work.outdir.has_abiext("DDB") for work in self]))

        # Final DDB file will be produced in the outdir of the work.
        out_ddb = self.outdir.path_in("out_DDB")
        desc = "DDB file merged by %s on %s" % (self.__class__.__name__, time.asctime())

        mrgddb = wrappers.Mrgddb(manager=self.manager, verbose=0)
        mrgddb.merge(self.outdir.path, ddb_files, out_ddb=out_ddb, description=desc)
        print("Final DDB file available at %s" % out_ddb)

        # Call the method of the super class.
        retcode = super().finalize()
        return retcode

Response: This method is called when the flow is completed.


Instruction:
Can you generate the documentation for the following Python 3 function
def from_scf_input(cls, workdir, scf_input, manager=None, allocate=True):
        flow = cls(workdir, manager=manager)

        flow.register_scf_task(scf_input)
        scf_task = flow[0][0]

        nl_work = DteWork.from_scf_task(scf_task)

        flow.register_work(nl_work)

        if allocate: flow.allocate()

        return flow

Response: Create a NonlinearFlow object from a GS - SCF run.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def from_global_moment_and_saxis(cls, global_moment, saxis):
        magmom = Magmom(global_moment)
        return cls(magmom.get_moment(saxis=saxis), saxis=saxis)

Response: Convenience method to initialize a new object from a given global Magmom and saxis.


Instruction:
Can you create a Python 3 function that
gets the magnetic moment relative to a given spin quantization axis.

Response:
def get_moment(self, saxis=(0, 0, 1)):
        """
        Get magnetic moment relative to a given spin quantization axis.
        If no axis is provided, moment will be given relative to the
        Magmom's internal spin quantization axis, i.e. equivalent to
        Magmom.moment

        :param axis: (list/numpy array) spin quantization axis
        :return: np.ndarray of length 3
        """

        # transform back to moment with spin axis [0, 0, 1]
        m_inv = self._get_transformation_matrix_inv(self.saxis)
        moment = np.matmul(self.moment, m_inv)

        # transform to new saxis
        m = self._get_transformation_matrix(saxis)
        moment = np.matmul(moment, m)

        # round small values to zero
        moment[np.abs(moment) < 1e-8] = 0

        return moment


Instruction:
Can you generate the documentation for the following Python 3 function
def have_consistent_saxis(magmoms):
        magmoms = [Magmom(magmom) for magmom in magmoms]
        ref_saxis = magmoms[0].saxis
        match_ref = [magmom.saxis == ref_saxis for magmom in magmoms]
        if np.all(match_ref):
            return True
        else:
            return False

Response: This method checks that all MAGMOM objects in a list have consistent spin quantization axis.


Instruction:
How would you explain what the following Python 3 function does
def are_collinear(magmoms):
        magmoms = [Magmom(magmom) for magmom in magmoms]
        if not Magmom.have_consistent_saxis(magmoms):
            magmoms = Magmom.get_consistent_set(magmoms)

        # convert to numpy array for convenience
        magmoms = np.array([list(magmom) for magmom in magmoms])
        magmoms = magmoms[np.any(magmoms, axis=1)] # remove zero magmoms
        if len(magmoms) == 0:
            return True

        # use first moment as reference to compare against
        ref_magmom = magmoms[0]
        # magnitude of cross products != 0 if non-collinear with reference
        num_ncl = np.count_nonzero(np.linalg.norm(np.cross(ref_magmom, magmoms), axis=1))
        if num_ncl > 0:
            return False
        else:
            return True

Response: Method checks to see if a set of magmoms are collinear with each other.


Instruction:
Write a Python 3 script for
creating a Magmom object from a magnetic moment provided relative to crystal axes.

Response:
def from_moment_relative_to_crystal_axes(cls, moment, lattice):
        """
        Obtaining a Magmom object from a magnetic moment provided
        relative to crystal axes.

        Used for obtaining moments from magCIF file.
        :param magmom: list of floats specifying vector magmom
        :param lattice: Lattice
        :return: Magmom
        """
        # get matrix representing unit lattice vectors
        unit_m = lattice.matrix / np.linalg.norm(lattice.matrix, axis=1)[:, None]
        moment = np.matmul(list(moment), unit_m)
        # round small values to zero
        moment[np.abs(moment) < 1e-8] = 0
        return cls(moment)


Instruction:
How would you explain what the following Python 3 function does
def get_moment_relative_to_crystal_axes(self, lattice):
        # get matrix representing unit lattice vectors
        unit_m = lattice.matrix / np.linalg.norm(lattice.matrix, axis=1)[:, None]
        # note np.matmul() requires numpy version >= 1.10
        moment = np.matmul(self.global_moment, np.linalg.inv(unit_m))
        # round small values to zero
        moment[np.abs(moment) < 1e-8] = 0
        return moment

Response: Returns the moments relative to the crystal axes of the magnetic CIF file.


Instruction:
Can you implement a function in Python 3 that
returns a Structure object from the Materials Project database via MP Rester.

Response:
def get_structure_from_mp(formula):
    """
    Convenience method to get a crystal from the Materials Project database via
    the API. Requires PMG_MAPI_KEY to be set.

    Args:
        formula (str): A formula

    Returns:
        (Structure) The lowest energy structure in Materials Project with that
            formula.
    """
    m = MPRester()
    entries = m.get_entries(formula, inc_structure="final")
    if len(entries) == 0:
        raise ValueError("No structure with formula %s in Materials Project!" %
                         formula)
    elif len(entries) > 1:
        warnings.warn("%d structures with formula %s found in Materials "
                      "Project. The lowest energy structure will be returned." %
                      (len(entries), formula))
    return min(entries, key=lambda e: e.energy_per_atom).structure


Instruction:
Given the following Python 3 function, write the documentation
def order_assimilation(args):
    (path, drone, data, status) = args
    newdata = drone.assimilate(path)
    if newdata:
        data.append(json.dumps(newdata, cls=MontyEncoder))
    status['count'] += 1
    count = status['count']
    total = status['total']
    logger.info('{}/{} ({:.2f}%) done'.format(count, total,
                                              count / total * 100))

Response: Internal helper method for BorgQueen to process assimilation


Instruction:
Create a Python 3 function to
assimilate the entire subdirectory structure in rootpath.

Response:
def parallel_assimilate(self, rootpath):
        """
        Assimilate the entire subdirectory structure in rootpath.
        """
        logger.info('Scanning for valid paths...')
        valid_paths = []
        for (parent, subdirs, files) in os.walk(rootpath):
            valid_paths.extend(self._drone.get_valid_paths((parent, subdirs,
                                                            files)))
        manager = Manager()
        data = manager.list()
        status = manager.dict()
        status['count'] = 0
        status['total'] = len(valid_paths)
        logger.info('{} valid paths found.'.format(len(valid_paths)))
        p = Pool(self._num_drones)
        p.map(order_assimilation, ((path, self._drone, data, status)
                                   for path in valid_paths))
        for d in data:
            self._data.append(json.loads(d, cls=MontyDecoder))


Instruction:
Here you have a function in Python 3, explain what it does
def serial_assimilate(self, rootpath):
        valid_paths = []
        for (parent, subdirs, files) in os.walk(rootpath):
            valid_paths.extend(self._drone.get_valid_paths((parent, subdirs,
                                                            files)))
        data = []
        count = 0
        total = len(valid_paths)
        for path in valid_paths:
            newdata = self._drone.assimilate(path)
            self._data.append(newdata)
            count += 1
            logger.info('{}/{} ({:.2f}%) done'.format(count, total,
                                                      count / total * 100))
        for d in data:
            self._data.append(json.loads(d, cls=MontyDecoder))

Response: Assimilate the entire subdirectory structure in rootpath serially.


Instruction:
Write a Python 3 script to
save the assimilated data to a file.

Response:
def save_data(self, filename):
        """
        Save the assimilated data to a file.

        Args:
            filename (str): filename to save the assimilated data to. Note
                that if the filename ends with gz or bz2, the relevant gzip
                or bz2 compression will be applied.
        """
        with zopen(filename, "wt") as f:
            json.dump(list(self._data), f, cls=MontyEncoder)


Instruction:
Explain what the following Python 3 code does
def load_data(self, filename):
        with zopen(filename, "rt") as f:
            self._data = json.load(f, cls=MontyDecoder)

Response: Load assimilated data from a file.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def eigenvectors_from_displacements(disp,masses):
    nphonons,natoms,ndirections = disp.shape
    sqrt_masses = np.sqrt(masses)
    return np.einsum("nax,a->nax",disp,sqrt_masses)

Response: Calculate the eigenvectors from the atomic displacements


Instruction:
Can you implement a function in Python 3 that
returns the point where the minimum frequency is reached and its value

Response:
def min_freq(self):
        """
        Returns the point where the minimum frequency is reached and its value
        """
        i = np.unravel_index(np.argmin(self.bands), self.bands.shape)

        return self.qpoints[i[1]], self.bands[i]


Instruction:
Can you implement a function in Python 3 that
returns the nac_frequencies for the given direction.

Response:
def get_nac_frequencies_along_dir(self, direction):
        """
        Returns the nac_frequencies for the given direction (not necessarily a versor).
        None if the direction is not present or nac_frequencies has not been calculated.

        Args:
            direction: the direction as a list of 3 elements
        Returns:
            the frequencies as a numpy array o(3*len(structure), len(qpoints)).
            None if not found.
        """
        versor = [i / np.linalg.norm(direction) for i in direction]
        for d, f in self.nac_frequencies:
            if np.allclose(versor, d):
                return f

        return None


Instruction:
Write a Python 3 script to
return the nac_eigendisplacements for the given direction.

Response:
def get_nac_eigendisplacements_along_dir(self, direction):
        """
        Returns the nac_eigendisplacements for the given direction (not necessarily a versor).
        None if the direction is not present or nac_eigendisplacements has not been calculated.

        Args:
            direction: the direction as a list of 3 elements
        Returns:
            the eigendisplacements as a numpy array of complex numbers with shape
            (3*len(structure), len(structure), 3). None if not found.
        """
        versor = [i / np.linalg.norm(direction) for i in direction]
        for d, e in self.nac_eigendisplacements:
            if np.allclose(versor, d):
                return e

        return None


Instruction:
How would you explain what the following Python 3 function does
def asr_breaking(self, tol_eigendisplacements=1e-5):

        for i in range(self.nb_qpoints):
            if np.allclose(self.qpoints[i].frac_coords, (0, 0, 0)):

                if self.has_eigendisplacements:
                    acoustic_modes_index = []
                    for j in range(self.nb_bands):
                        eig = self.eigendisplacements[j][i]
                        if np.max(np.abs(eig[1:] - eig[:1])) < tol_eigendisplacements:
                            acoustic_modes_index.append(j)
                    # if acoustic modes are not correctly identified return use
                    # the first three modes
                    if len(acoustic_modes_index) != 3:
                        acoustic_modes_index = [0, 1, 2]
                    return self.bands[acoustic_modes_index, i]
                else:
                    return self.bands[:3, i]

        return None

Response: Returns the breaking of the acoustic sum rule for the three acoustic modes and the first three bands.


Instruction:
Can you implement a function in Python 3 that
returns the list of equivalent qpoints to the given index.

Response:
def get_equivalent_qpoints(self, index):
        """
        Returns the list of qpoint indices equivalent (meaning they are the
        same frac coords) to the given one.

        Args:
            index: the qpoint index

        Returns:
            a list of equivalent indices

        TODO: now it uses the label we might want to use coordinates instead
        (in case there was a mislabel)
        """
        #if the qpoint has no label it can"t have a repetition along the band
        #structure line object

        if self.qpoints[index].label is None:
            return [index]

        list_index_qpoints = []
        for i in range(self.nb_qpoints):
            if self.qpoints[i].label == self.qpoints[index].label:
                list_index_qpoints.append(i)

        return list_index_qpoints


Instruction:
Can you generate the documentation for the following Python 3 function
def get_branch(self, index):
        to_return = []
        for i in self.get_equivalent_qpoints(index):
            for b in self.branches:
                    if b["start_index"] <= i <= b["end_index"]:
                        to_return.append({"name": b["name"],
                                          "start_index": b["start_index"],
                                          "end_index": b["end_index"],
                                          "index": i})
        return to_return

Response:
Returns in what branches are in which the qpoint is. There can be several
            branches.


Instruction:
Can you tell what is the following Python 3 function doing
def write_phononwebsite(self,filename):
        import json
        with open(filename,'w') as f:
            phononwebsite_json = json.dump(self.as_phononwebsite(),f)

Response: Write a json file for the phononwebsite


Instruction:
Write a Python 3 function that can
return a dictionary with the phononwebsite format for the current state of the object.

Response:
def as_phononwebsite(self):
        """
        Return a dictionary with the phononwebsite format:
        http://henriquemiranda.github.io/phononwebsite
        """
        d = {}

        #define the lattice
        d["lattice"] = self.structure.lattice._matrix.tolist()

        #define atoms
        atom_pos_car = []
        atom_pos_red = []
        atom_types = []
        for site in self.structure.sites:
            atom_pos_car.append(site.coords.tolist())
            atom_pos_red.append(site.frac_coords.tolist())
            atom_types.append(site.species_string)

        #default for now
        d["repetitions"] = get_reasonable_repetitions(len(atom_pos_car))

        d["natoms"] = len(atom_pos_car)
        d["atom_pos_car"] = atom_pos_car
        d["atom_pos_red"] = atom_pos_red
        d["atom_types"] = atom_types
        d["atom_numbers"] = self.structure.atomic_numbers
        d["formula"] = self.structure.formula
        d["name"] = self.structure.formula

        #get qpoints
        qpoints = []
        for q in self.qpoints:
            qpoints.append(list(q.frac_coords))
        d["qpoints"] = qpoints

        # get labels
        hsq_dict = collections.OrderedDict()
        for nq,q in enumerate(self.qpoints):
            if q.label is not None:
                hsq_dict[nq] = q.label

        #get distances
        dist = 0
        nqstart = 0
        distances = [dist]
        line_breaks = []
        for nq in range(1,len(qpoints)):
            q1 = np.array(qpoints[nq])
            q2 = np.array(qpoints[nq-1])
            #detect jumps
            if ((nq in hsq_dict) and (nq-1 in hsq_dict)):
                if (hsq_dict[nq] != hsq_dict[nq-1]):
                    hsq_dict[nq-1] += "|"+hsq_dict[nq]
                del hsq_dict[nq]
                line_breaks.append((nqstart,nq))
                nqstart = nq
            else:
                dist += np.linalg.norm(q1-q2)
            distances.append(dist)
        line_breaks.append((nqstart,len(qpoints)))
        d["distances"] = distances
        d["line_breaks"] = line_breaks
        d["highsym_qpts"] = list(hsq_dict.items())

        #eigenvalues
        thz2cm1 = 33.35641
        bands = self.bands.copy()*thz2cm1
        d["eigenvalues"] = bands.T.tolist()

        #eigenvectors
        eigenvectors = self.eigendisplacements.copy()
        eigenvectors /= np.linalg.norm(eigenvectors[0,0])
        eigenvectors = eigenvectors.swapaxes(0,1)
        eigenvectors = np.array([eigenvectors.real, eigenvectors.imag])
        eigenvectors = np.rollaxis(eigenvectors,0,5)
        d["vectors"] = eigenvectors.tolist()

        return d


Instruction:
Can you tell what is the following Python 3 function doing
def band_reorder(self):
        eiv = self.eigendisplacements
        eig = self.bands

        nphonons,nqpoints = self.bands.shape
        order = np.zeros([nqpoints,nphonons],dtype=int)
        order[0] = np.array(range(nphonons))

        #get the atomic masses
        atomic_masses = [ site.specie.atomic_mass for site in self.structure.sites ]

        #get order
        for nq in range(1,nqpoints):
            old_eiv = eigenvectors_from_displacements(eiv[:,nq-1],atomic_masses)
            new_eiv = eigenvectors_from_displacements(eiv[:,nq],  atomic_masses)
            order[nq] = estimate_band_connection(old_eiv.reshape([nphonons,nphonons]).T,
                                                 new_eiv.reshape([nphonons,nphonons]).T,
                                                 order[nq-1])

        #reorder
        for nq in range(1,nqpoints):
            eivq=eiv[:,nq]
            eigq=eig[:,nq]
            eiv[:,nq] = eivq[order[nq]]
            eig[:,nq] = eigq[order[nq]]

Response: Re - order the eigenvalues according to the similarity of the eigenvalues of the two structure objects.


Instruction:
How would you implement a function in Python 3 that
writes a batch of vasp input files for a sequence of transformed structures to a single directory.

Response:
def batch_write_vasp_input(transformed_structures, vasp_input_set=MPRelaxSet,
                           output_dir=".", create_directory=True,
                           subfolder=None,
                           include_cif=False, **kwargs):
    """
    Batch write vasp input for a sequence of transformed structures to
    output_dir, following the format output_dir/{group}/{formula}_{number}.

    Args:
        transformed_structures: Sequence of TransformedStructures.
        vasp_input_set: pymatgen.io.vaspio_set.VaspInputSet to creates
            vasp input files from structures.
        output_dir: Directory to output files
        create_directory (bool): Create the directory if not present.
            Defaults to True.
        subfolder: Function to create subdirectory name from
            transformed_structure.
            e.g., lambda x: x.other_parameters["tags"][0] to use the first
            tag.
        include_cif (bool): Boolean indication whether to output a CIF as
            well. CIF files are generally better supported in visualization
            programs.
    """
    for i, s in enumerate(transformed_structures):
        formula = re.sub(r"\s+", "", s.final_structure.formula)
        if subfolder is not None:
            subdir = subfolder(s)
            dirname = os.path.join(output_dir, subdir,
                                   "{}_{}".format(formula, i))
        else:
            dirname = os.path.join(output_dir, "{}_{}".format(formula, i))
        s.write_vasp_input(vasp_input_set, dirname,
                           create_directory=create_directory, **kwargs)
        if include_cif:
            from pymatgen.io.cif import CifWriter

            writer = CifWriter(s.final_structure)
            writer.write_file(os.path.join(dirname, "{}.cif".format(formula)))


Instruction:
Here you have a function in Python 3, explain what it does
def append_transformation(self, transformation, extend_collection=False,
                              clear_redo=True):
        """
        Appends a transformation to all TransformedStructures.

        Args:
            transformation: Transformation to append
            extend_collection: Whether to use more than one output structure
                from one-to-many transformations. extend_collection can be a
                number, which determines the maximum branching for each
                transformation.
            clear_redo (bool): Whether to clear the redo list. By default,
                this is True, meaning any appends clears the history of
                undoing. However, when using append_transformation to do a
                redo, the redo list should not be cleared to allow multiple
                redos.

        Returns:
            List of booleans corresponding to initial transformed structures
            each boolean describes whether the transformation altered the
            structure
        """
        if self.ncores and transformation.use_multiprocessing:
            p = Pool(self.ncores)
            # need to condense arguments into single tuple to use map
            z = map(
                lambda x: (x, transformation, extend_collection, clear_redo),
                self.transformed_structures)
            new_tstructs = p.map(_apply_transformation, z, 1)
            self.transformed_structures = []
            for ts in new_tstructs:
                self.transformed_structures.extend(ts)
        else:
            new_structures = []
            for x in self.transformed_structures:
                new = x.append_transformation(transformation,
                                              extend_collection,
                                              clear_redo=clear_redo)
                if new is not None:
                    new_structures.extend(new)
            self.transformed_structures.extend(new_structures)

Response: Appends a transformation to all TransformedStructures in the current TransformedStructures.


Instruction:
Explain what the following Python 3 code does
def apply_filter(self, structure_filter):

        def test_transformed_structure(ts):
            return structure_filter.test(ts.final_structure)

        self.transformed_structures = list(filter(test_transformed_structure,
                                                  self.transformed_structures))
        for ts in self.transformed_structures:
            ts.append_filter(structure_filter)

Response:
Applies a structure_filter to the list of TransformedStructures
            in the transmuter.


Instruction:
Write a Python 3 function that can
set the value of a parameter in the transmuter.

Response:
def set_parameter(self, key, value):
        """
        Add parameters to the transmuter. Additional parameters are stored in
        the as_dict() output.

        Args:
            key: The key for the parameter.
            value: The value for the parameter.
        """
        for x in self.transformed_structures:
            x.other_parameters[key] = value


Instruction:
Make a summary of the following Python 3 code
def append_transformed_structures(self, tstructs_or_transmuter):
        if isinstance(tstructs_or_transmuter, self.__class__):
            self.transformed_structures.extend(tstructs_or_transmuter
                                               .transformed_structures)
        else:
            for ts in tstructs_or_transmuter:
                assert isinstance(ts, TransformedStructure)
            self.transformed_structures.extend(tstructs_or_transmuter)

Response: Method appends the transformed structures to the transmuter list.


Instruction:
Given the following Python 3 function, write the documentation
def from_structures(structures, transformations=None, extend_collection=0):
        tstruct = [TransformedStructure(s, []) for s in structures]
        return StandardTransmuter(tstruct, transformations, extend_collection)

Response: This is a convenience method for creating a new instance of the Alternative class from a sequence of structures.


Instruction:
Can you generate the documentation for the following Python 3 function
def from_filenames(filenames, transformations=None, primitive=True,
                       extend_collection=False):
        """
        Generates a TransformedStructureCollection from a cif, possibly
        containing multiple structures.

        Args:
            filenames: List of strings of the cif files
            transformations: New transformations to be applied to all
                structures
            primitive: Same meaning as in __init__.
            extend_collection: Same meaning as in __init__.
        """

        allcifs = []
        for fname in filenames:
            with open(fname, "r") as f:
                allcifs.append(f.read())
        return CifTransmuter("\n".join(allcifs), transformations,
                             primitive=primitive,
                             extend_collection=extend_collection)

Response: Generates a TransformedStructureCollection from a list of filenames.


Instruction:
Create a Python 3 function for
parsing the SCF cycle and return a dictionary of the names of columns and values.

Response:
def _magic_parser(stream, magic):
    """
    Parse the section with the SCF cycle

    Returns:
        dict where the key are the name of columns and
        the values are list of numbers. Note if no section was found.

    .. warning::

        The parser is very fragile and should be replaced by YAML.
    """
    #Example (SCF cycle, similar format is used for phonons):
    #
    #  iter   Etot(hartree)      deltaE(h)  residm     vres2
    #  ETOT  1  -8.8604027880849    -8.860E+00 2.458E-02 3.748E+00

    #  At SCF step    5       vres2   =  3.53E-08 < tolvrs=  1.00E-06 =>converged.
    in_doc, fields = 0, None

    for line in stream:
        line = line.strip()

        if line.startswith(magic):
            keys = line.split()
            fields = OrderedDict((k, []) for k in keys)

        if fields is not None:
            #print(line)
            in_doc += 1
            if in_doc == 1:
                continue

            # End of the section.
            if not line: break

            tokens = list(map(float, line.split()[1:]))
            assert len(tokens) == len(keys)
            for l, v in zip(fields.values(), tokens):
                l.append(v)

    # Convert values to numpy arrays.
    if fields:
        return OrderedDict([(k, np.array(v)) for k, v in fields.items()])
    else:
        return None


Instruction:
Make a summary of the following Python 3 code
def yaml_read_kpoints(filename, doc_tag="!Kpoints"):
    with YamlTokenizer(filename) as r:
        doc = r.next_doc_with_tag(doc_tag)
        d = yaml.safe_load(doc.text_notag)

        return np.array(d["reduced_coordinates_of_qpoints"])

Response: Read the K - points from file.


Instruction:
Here you have a function in Python 3, explain what it does
def yaml_read_irred_perts(filename, doc_tag="!IrredPerts"):
    with YamlTokenizer(filename) as r:
        doc = r.next_doc_with_tag(doc_tag)
        d = yaml.safe_load(doc.text_notag)

        return [AttrDict(**pert) for pert in d["irred_perts"]]

Response: Read the list of irreducible perturbations from file.


Instruction:
Given the following Python 3 function, write the documentation
def to_string(self, verbose=0):
        rows = [[it + 1] + list(map(str, (self[k][it] for k in self.keys())))
                for it in range(self.num_iterations)]

        return tabulate(rows, headers=["Iter"] + list(self.keys()))

Response: String representation of the object.


Instruction:
How would you explain what the following Python 3 function does
def from_stream(cls, stream):
        fields = _magic_parser(stream, magic=cls.MAGIC)

        if fields:
            fields.pop("iter")
            return cls(fields)
        else:
            return None

Response: Read the first occurrence of ScfCycle from stream.


Instruction:
Can you tell what is the following Python 3 function doing
def add_label_cycle(self, label, cycle):
        self.labels.append(label)
        self.cycles.append(cycle)

Response: Add a cycle to the plotter with label label.


Instruction:
Implement a function in Python 3 to
plot multiple cycels on a grid per quantity.

Response:
def combiplot(self, fontsize=8, **kwargs):
        """
        Compare multiple cycels on a grid: one subplot per quantity,
        all cycles on the same subplot.

        Args:
            fontsize: Legend fontsize.
        """
        ax_list = None
        for i, (label, cycle) in enumerate(self.items()):
            fig = cycle.plot(ax_list=ax_list, label=label, fontsize=fontsize,
                             lw=2.0, marker="o", linestyle="-", show=False)
            ax_list = fig.axes

        return fig


Instruction:
Given the following Python 3 function, write the documentation
def slideshow(self, **kwargs):
        for label, cycle in self.items():
            cycle.plot(title=label, tight_layout=True)

Response: Produce slideshow of the different cycles. One plot per cycle.


Instruction:
Write a Python 3 function that can
string representation of the set of related items.

Response:
def to_string(self, verbose=0):
        """String representation."""
        lines = []
        app = lines.append
        for i, cycle in enumerate(self):
            app("")
            app("RELAXATION STEP: %d" % (i + 1))
            app(cycle.to_string(verbose=verbose))

        return "\n".join(lines)


Instruction:
Implement a function in Python 3 to
extract data from stream. Returns None if some error occurred.

Response:
def from_stream(cls, stream):
        """
        Extract data from stream. Returns None if some error occurred.
        """
        cycles = []
        while True:
            scf_cycle = GroundStateScfCycle.from_stream(stream)
            if scf_cycle is None: break
            cycles.append(scf_cycle)

        return cls(cycles) if cycles else None


Instruction:
Can you tell what is the following Python 3 function doing
def history(self):
        history = OrderedDict()
        for cycle in self:
            d = cycle.last_iteration
            for k, v in d.items():
                if k in history:
                    history[k].append(v)
                else:
                    history[k] = [v]

        # Convert to numpy arrays.
        for k, v in history.items():
            history[k] = np.array(v)

        return history

Response:
Returns an ordered dictionary of lists with the evolution of
            the data as function of the relaxation step.


Instruction:
Can you create a Python 3 function that
uses matplotlib to plot the evolution of the structural relaxation.

Response:
def slideshow(self, **kwargs):
        """
        Uses matplotlib to plot the evolution of the structural relaxation.

        Args:
            ax_list: List of axes. If None a new figure is produced.

        Returns:
            `matplotlib` figure
        """
        for i, cycle in enumerate(self.cycles):
            cycle.plot(title="Relaxation step %s" % (i + 1),
                       tight_layout=kwargs.pop("tight_layout", True),
                       show=kwargs.pop("show", True))


Instruction:
Write a Python 3 function that can
plot relaxation history i. e. the results of the last iteration of each SCF cycle.

Response:
def plot(self, ax_list=None, fontsize=12, **kwargs):
        """
        Plot relaxation history i.e. the results of the last iteration of each SCF cycle.

        Args:
            ax_list: List of axes. If None a new figure is produced.
            fontsize: legend fontsize.
            kwargs: keyword arguments are passed to ax.plot

        Returns: matplotlib figure
        """
        history = self.history

        # Build grid of plots.
        num_plots, ncols, nrows = len(history), 1, 1
        if num_plots > 1:
            ncols = 2
            nrows = num_plots // ncols + num_plots % ncols

        ax_list, fig, plot = get_axarray_fig_plt(ax_list, nrows=nrows, ncols=ncols,
                                                 sharex=True, sharey=False, squeeze=False)
        ax_list = np.array(ax_list).ravel()

        iter_num = np.array(list(range(self.num_iterations))) + 1
        label = kwargs.pop("label", None)

        for i, ((key, values), ax) in enumerate(zip(history.items(), ax_list)):
            ax.grid(True)
            ax.set_xlabel('Relaxation Step')
            ax.set_xticks(iter_num, minor=False)
            ax.set_ylabel(key)

            xx, yy = iter_num, values
            if not kwargs and label is None:
                ax.plot(xx, yy, "-o", lw=2.0)
            else:
                ax.plot(xx, yy, label=label if i == 0 else None, **kwargs)

            if key in _VARS_SUPPORTING_LOGSCALE and np.all(yy > 1e-22):
                ax.set_yscale("log")

            if key in _VARS_WITH_YRANGE:
                ymin, ymax = _VARS_WITH_YRANGE[key]
                val_min, val_max = np.min(yy), np.max(yy)
                if abs(val_max - val_min) > abs(ymax - ymin):
                    ax.set_ylim(ymin, ymax)

            if label is not None:
                ax.legend(loc="best", fontsize=fontsize, shadow=True)

        # Get around a bug in matplotlib.
        if num_plots % ncols != 0:
            ax_list[-1].plot(xx, yy, lw=0.0)
            ax_list[-1].axis('off')

        return fig


Instruction:
Create a Python 3 function to
move to new file position.

Response:
def seek(self, offset, whence=0):
        """
        seek(offset[, whence]) -> None.  Move to new file position.

        Argument offset is a byte count.  Optional argument whence defaults to
        0 (offset from start of file, offset should be >= 0); other values are 1
        (move relative to current position, positive or negative), and 2 (move
        relative to end of file, usually negative, although many platforms allow
        seeking beyond the end of a file).  If the file is opened in text mode,
        only offsets returned by tell() are legal.  Use of other offsets causes
        undefined behavior.
        Note that not all file objects are seekable.
        """
        assert offset == 0
        self.linepos = 0
        return self.stream.seek(offset, whence)


Instruction:
How would you code a function in Python 3 to
return the next YAML document in the stream.

Response:
def next(self):
        """
        Returns the first YAML document in stream.

        .. warning::

            Assume that the YAML document are closed explicitely with the sentinel '...'
        """
        in_doc, lines, doc_tag = None, [], None

        for i, line in enumerate(self.stream):
            self.linepos += 1
            #print(i, line)

            if line.startswith("---"):
                # Include only lines in the form:
                #  "--- !tag"
                #  "---"
                # Other lines are spurious.
                in_doc = False
                l = line[3:].strip().lstrip()

                if l.startswith("!"):
                    # "--- !tag"
                    doc_tag = l
                    in_doc = True
                elif not l:
                    #  "---"
                    in_doc = True
                    doc_tag = None

                if in_doc:
                    lineno = self.linepos

            if in_doc:
                lines.append(line)

            if in_doc and line.startswith("..."):
                return YamlDoc(text="".join(lines), lineno=lineno, tag=doc_tag)

        raise StopIteration("Cannot find next YAML document in %s" % self.filename)


Instruction:
Make a summary of the following Python 3 code
def next_doc_with_tag(self, doc_tag):
        while True:
            try:
                doc = next(self)
                if doc.tag == doc_tag:
                    return doc

            except StopIteration:
                raise

Response: Returns the next document with the specified tag. Empty string is no doc is found.


Instruction:
Create a Python 3 function for
returning all the documents with the specified tag.

Response:
def all_docs_with_tag(self, doc_tag):
        """
        Returns all the documents with the specified tag.
        """
        docs = []

        while True:
            try:
                doc = self.next_doc_with(doc_tag)
                docs.append(doc)

            except StopIteration:
                break

        self.seek(0)
        return docs


Instruction:
How would you implement a function in Python 3 that
returns the YAML text without the tag.

Response:
def text_notag(self):
        """
        Returns the YAML text without the tag.
        Useful if we don't have any constructor registered for the tag
        (we used the tag just to locate the document).
        """
        if self.tag is not None:
            return self.text.replace(self.tag, "")
        else:
            return self.text


Instruction:
Explain what the following Python 3 code does
def _execute(self, workdir, with_mpirun=False, exec_args=None):
        qadapter = self.manager.qadapter
        if not with_mpirun: qadapter.name = None
        if self.verbose:
            print("Working in:", workdir)

        script = qadapter.get_script_str(
            job_name=self.name,
            launch_dir=workdir,
            executable=self.executable,
            qout_path="qout_file.path",
            qerr_path="qerr_file.path",
            stdin=self.stdin_fname,
            stdout=self.stdout_fname,
            stderr=self.stderr_fname,
            exec_args=exec_args
        )

        # Write the script.
        script_file = os.path.join(workdir, "run" + self.name + ".sh")
        with open(script_file, "w") as fh:
            fh.write(script)
            os.chmod(script_file, 0o740)

        qjob, process = qadapter.submit_to_queue(script_file)
        self.stdout_data, self.stderr_data = process.communicate()
        self.returncode = process.returncode
        #raise self.Error("%s returned %s\n cmd_str: %s" % (self, self.returncode, self.cmd_str))

        return self.returncode

Response: Execute the executable in a subprocess inside workdir.


Instruction:
Here you have a function in Python 3, explain what it does
def merge_qpoints(self, workdir, files_to_merge, out_prefix):
        # We work with absolute paths.
        files_to_merge = [os.path.abspath(s) for s in list_strings(files_to_merge)]
        nfiles = len(files_to_merge)

        if self.verbose:
            print("Will merge %d files with output_prefix %s" % (nfiles, out_prefix))
            for (i, f) in enumerate(files_to_merge):
                print(" [%d] %s" % (i, f))

        if nfiles == 1:
            raise self.Error("merge_qpoints does not support nfiles == 1")

        self.stdin_fname, self.stdout_fname, self.stderr_fname = \
            map(os.path.join, 3 * [workdir], ["mrgscr.stdin", "mrgscr.stdout", "mrgscr.stderr"])

        inp = StringIO()
        inp.write(str(nfiles) + "\n")     # Number of files to merge.
        inp.write(out_prefix + "\n")      # Prefix for the final output file:

        for filename in files_to_merge:
            inp.write(filename + "\n")   # List with the files to merge.

        inp.write("1\n")                 # Option for merging q-points.

        self.stdin_data = [s for s in inp.getvalue()]

        with open(self.stdin_fname, "w") as fh:
            fh.writelines(self.stdin_data)
            # Force OS to write data to disk.
            fh.flush()
            os.fsync(fh.fileno())

        self.execute(workdir)

Response: Execute mrgscr inside directory workdir to merge files_to_merge and produce new file with prefix out_prefix.


Instruction:
Make a summary of the following Python 3 code
def merge(self, workdir, gswfk_file, dfpt_files, gkk_files, out_gkk, binascii=0):
        raise NotImplementedError("This method should be tested")
        #out_gkk = out_gkk if cwd is None else os.path.join(os.path.abspath(cwd), out_gkk)

        # We work with absolute paths.
        gswfk_file = os.path.absath(gswfk_file)
        dfpt_files = [os.path.abspath(s) for s in list_strings(dfpt_files)]
        gkk_files = [os.path.abspath(s) for s in list_strings(gkk_files)]

        print("Will merge %d 1WF files, %d GKK file in output %s" %
              (len(dfpt_files), len(gkk_files), out_gkk))

        if self.verbose:
            for i, f in enumerate(dfpt_files): print(" [%d] 1WF %s" % (i, f))
            for i, f in enumerate(gkk_files): print(" [%d] GKK %s" % (i, f))

        self.stdin_fname, self.stdout_fname, self.stderr_fname = \
            map(os.path.join, 3 * [workdir], ["mrggkk.stdin", "mrggkk.stdout", "mrggkk.stderr"])

        inp = StringIO()
        inp.write(out_gkk + "\n")        # Name of the output file
        inp.write(str(binascii) + "\n")  # Integer flag: 0 --> binary output, 1 --> ascii formatted output
        inp.write(gswfk_file + "\n")     # Name of the groud state wavefunction file WF

        #dims = len(dfpt_files, gkk_files, ?)
        dims = " ".join([str(d) for d in dims])
        inp.write(dims + "\n")             # Number of 1WF, of GKK files, and number of 1WF files in all the GKK files

        # Names of the 1WF files...
        for fname in dfpt_files:
            inp.write(fname + "\n")

        # Names of the GKK files...
        for fname in gkk_files:
            inp.write(fname + "\n")

        self.stdin_data = [s for s in inp.getvalue()]

        with open(self.stdin_fname, "w") as fh:
            fh.writelines(self.stdin_data)
            # Force OS to write data to disk.
            fh.flush()
            os.fsync(fh.fileno())

        self.execute(workdir)

        return out_gkk

Response: This method merges the GKK files into one database file.


Instruction:
Here you have a function in Python 3, explain what it does
def merge(self, workdir, ddb_files, out_ddb, description, delete_source_ddbs=True):
        # We work with absolute paths.
        ddb_files = [os.path.abspath(s) for s in list_strings(ddb_files)]
        if not os.path.isabs(out_ddb):
            out_ddb = os.path.join(os.path.abspath(workdir), os.path.basename(out_ddb))

        if self.verbose:
            print("Will merge %d files into output DDB %s" % (len(ddb_files), out_ddb))
            for i, f in enumerate(ddb_files):
                print(" [%d] %s" % (i, f))

        # Handle the case of a single file since mrgddb uses 1 to denote GS files!
        if len(ddb_files) == 1:
            with open(ddb_files[0], "r") as inh, open(out_ddb, "w") as out:
                for line in inh:
                    out.write(line)
            return out_ddb

        self.stdin_fname, self.stdout_fname, self.stderr_fname = \
            map(os.path.join, 3 * [os.path.abspath(workdir)], ["mrgddb.stdin", "mrgddb.stdout", "mrgddb.stderr"])

        inp = StringIO()
        inp.write(out_ddb + "\n")              # Name of the output file.
        inp.write(str(description) + "\n")     # Description.
        inp.write(str(len(ddb_files)) + "\n")  # Number of input DDBs.

        # Names of the DDB files.
        for fname in ddb_files:
            inp.write(fname + "\n")

        self.stdin_data = [s for s in inp.getvalue()]

        with open(self.stdin_fname, "wt") as fh:
            fh.writelines(self.stdin_data)
            # Force OS to write data to disk.
            fh.flush()
            os.fsync(fh.fileno())

        retcode = self.execute(workdir, exec_args=['--nostrict'])
        if retcode == 0 and delete_source_ddbs:
            # Remove ddb files.
            for f in ddb_files:
                try:
                    os.remove(f)
                except IOError:
                    pass

        return out_ddb

Response: Merge the DDB files into a single file.


Instruction:
Can you generate the documentation for the following Python 3 function
def merge(self, workdir, pot_files, out_dvdb, delete_source=True):
        # We work with absolute paths.
        pot_files = [os.path.abspath(s) for s in list_strings(pot_files)]
        if not os.path.isabs(out_dvdb):
            out_dvdb = os.path.join(os.path.abspath(workdir), os.path.basename(out_dvdb))

        if self.verbose:
            print("Will merge %d files into output DVDB %s" % (len(pot_files), out_dvdb))
            for i, f in enumerate(pot_files):
                print(" [%d] %s" % (i, f))

        # Handle the case of a single file since mrgddb uses 1 to denote GS files!
        if len(pot_files) == 1:
            with open(pot_files[0], "r") as inh, open(out_dvdb, "w") as out:
                for line in inh:
                    out.write(line)
            return out_dvdb

        self.stdin_fname, self.stdout_fname, self.stderr_fname = \
            map(os.path.join, 3 * [os.path.abspath(workdir)], ["mrgdvdb.stdin", "mrgdvdb.stdout", "mrgdvdb.stderr"])

        inp = StringIO()
        inp.write(out_dvdb + "\n")             # Name of the output file.
        inp.write(str(len(pot_files)) + "\n")  # Number of input POT files.

        # Names of the POT files.
        for fname in pot_files:
            inp.write(fname + "\n")

        self.stdin_data = [s for s in inp.getvalue()]

        with open(self.stdin_fname, "wt") as fh:
            fh.writelines(self.stdin_data)
            # Force OS to write data to disk.
            fh.flush()
            os.fsync(fh.fileno())

        retcode = self.execute(workdir)
        if retcode == 0 and delete_source:
            # Remove pot files.
            for f in pot_files:
                try:
                    os.remove(f)
                except IOError:
                    pass

        return out_dvdb

Response: Merge POT files into a single DVDB file.


Instruction:
Implement a function in Python 3 to
run cut3d on the specified workdir and returns the standard output and the output filepath.

Response:
def cut3d(self, cut3d_input, workdir):
        """
        Runs cut3d with a Cut3DInput

        Args:
            cut3d_input: a Cut3DInput object.
            workdir: directory where cut3d is executed.

        Returns:
            (string) absolute path to the standard output of the cut3d execution.
            (string) absolute path to the output filepath. None if output is required.
        """
        self.stdin_fname, self.stdout_fname, self.stderr_fname = \
            map(os.path.join, 3 * [os.path.abspath(workdir)], ["cut3d.stdin", "cut3d.stdout", "cut3d.stderr"])

        cut3d_input.write(self.stdin_fname)

        retcode = self._execute(workdir, with_mpirun=False)

        if retcode != 0:
            raise RuntimeError("Error while running cut3d in %s." % workdir)

        output_filepath = cut3d_input.output_filepath

        if output_filepath is not None:
            if not os.path.isabs(output_filepath):
                output_filepath = os.path.abspath(os.path.join(workdir, output_filepath))

            if not os.path.isfile(output_filepath):
                raise RuntimeError("The file was not converted correctly in %s." % workdir)

        return self.stdout_fname, output_filepath


Instruction:
Make a summary of the following Python 3 code
def from_path(cls, path, suffix=''):

        def _get_filepath(filename, warning, path=path, suffix=suffix):
            paths = glob.glob(os.path.join(path, filename + suffix + '*'))
            if not paths:
                warnings.warn(warning)
                return None
            if len(paths) > 1:
                # using reverse=True because, if multiple files are present,
                # they likely have suffixes 'static', 'relax', 'relax2', etc.
                # and this would give 'static' over 'relax2' over 'relax'
                # however, better to use 'suffix' kwarg to avoid this!
                paths.sort(reverse=True)
                warnings.warn('Multiple files detected, using {}'.format(os.path.basename(path)))
            path = paths[0]
            return path

        chgcar_path = _get_filepath('CHGCAR', 'Could not find CHGCAR!')
        chgcar = Chgcar.from_file(chgcar_path)

        aeccar0_path = _get_filepath('AECCAR0', 'Could not find AECCAR0, interpret Bader results with caution.')
        aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

        aeccar2_path = _get_filepath('AECCAR2', 'Could not find AECCAR2, interpret Bader results with caution.')
        aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

        chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0 and aeccar2) else None

        return cls(chgcar.structure, chgcar, chgcar_ref)

Response: This method creates a new instance of the class from a path to a VASP file.


Instruction:
Can you create a Python 3 function that
returns the ellipticity of the species.

Response:
def ellipticity(self):
        '''
        Most meaningful for bond critical points,
        can be physically interpreted as e.g. degree
        of pi-bonding in organic molecules. Consult
        literature for more information.
        :return:
        '''
        eig = np.linalg.eig(self.field_hessian)
        eig.sort()
        return eig[0]/eig[1] - 1


Instruction:
Explain what the following Python 3 code does
def structure_graph(self, edge_weight="bond_length", edge_weight_units="Å"):

        sg = StructureGraph.with_empty_graph(self.structure, name="bonds",
                                             edge_weight_name=edge_weight,
                                             edge_weight_units=edge_weight_units)

        edges = self.edges.copy()
        idx_to_delete = []
        # check for duplicate bonds
        for idx, edge in edges.items():
            unique_idx = self.nodes[idx]['unique_idx']
            # only check edges representing bonds, not rings
            if self.critical_points[unique_idx].type == CriticalPointType.bond:
                if idx not in idx_to_delete:
                    for idx2, edge2 in edges.items():
                        if idx != idx2 and edge == edge2:
                            idx_to_delete.append(idx2)
                            warnings.warn("Duplicate edge detected, try re-running "
                                          "critic2 with custom parameters to fix this. "
                                          "Mostly harmless unless user is also "
                                          "interested in rings/cages.")
                            logger.debug("Duplicate edge between points {} (unique point {})"
                                         "and {} ({}).".format(idx, self.nodes[idx]['unique_idx'],
                                                               idx2, self.nodes[idx2]['unique_idx']))
        # and remove any duplicate bonds present
        for idx in idx_to_delete:
            del edges[idx]

        for idx, edge in edges.items():
            unique_idx = self.nodes[idx]['unique_idx']
            # only add edges representing bonds, not rings
            if self.critical_points[unique_idx].type == CriticalPointType.bond:

                from_idx = edge['from_idx']
                to_idx = edge['to_idx']

                from_lvec = edge['from_lvec']
                to_lvec = edge['to_lvec']

                relative_lvec = np.subtract(to_lvec, from_lvec)

                if edge_weight == "bond_length":
                    weight = self.structure.get_distance(from_idx, to_idx, jimage=relative_lvec)
                else:
                    weight = getattr(self.critical_points[unique_idx],
                                     edge_weight, None)

                sg.add_edge(from_idx, to_idx,
                            from_jimage=from_lvec, to_jimage=to_lvec,
                            weight=weight)

        return sg

Response: Returns a StructureGraph object describing the bonding information for the current crystal.


Instruction:
Explain what the following Python 3 code does
def _add_node(self, idx, unique_idx, frac_coords):
        self.nodes[idx] = {'unique_idx': unique_idx, 'frac_coords': frac_coords}

Response: Add information about a node describing a critical point.


Instruction:
Write a Python 3 function for
adding an edge linking two critical points to the graph.

Response:
def _add_edge(self, idx, from_idx, from_lvec, to_idx, to_lvec):
        """
        Add information about an edge linking two critical points.

        This actually describes two edges:

        from_idx ------ idx ------ to_idx

        However, in practice, from_idx and to_idx will typically be
        atom nuclei, with the center node (idx) referring to a bond
        critical point. Thus, it will be more convenient to model
        this as a single edge linking nuclei with the properties
        of the bond critical point stored as an edge attribute.

        :param idx: index of node
        :param from_idx: from index of node
        :param from_lvec: vector of lattice image the from node is in
        as tuple of ints
        :param to_idx: to index of node
        :param to_lvec:  vector of lattice image the to node is in as
        tuple of ints
        :return:
        """
        self.edges[idx] = {'from_idx': from_idx, 'from_lvec': from_lvec,
                           'to_idx': to_idx, 'to_lvec': to_lvec}


Instruction:
Make a summary of the following Python 3 code
def calculate_bv_sum(site, nn_list, scale_factor=1.0):
    el1 = Element(site.specie.symbol)
    bvsum = 0
    for (nn, dist) in nn_list:
        el2 = Element(nn.specie.symbol)
        if (el1 in ELECTRONEG or el2 in ELECTRONEG) and el1 != el2:
            r1 = BV_PARAMS[el1]["r"]
            r2 = BV_PARAMS[el2]["r"]
            c1 = BV_PARAMS[el1]["c"]
            c2 = BV_PARAMS[el2]["c"]
            R = r1 + r2 - r1 * r2 * (sqrt(c1) - sqrt(c2)) ** 2 / \
                (c1 * r1 + c2 * r2)
            vij = exp((R - dist * scale_factor) / 0.31)
            bvsum += vij * (1 if el1.X < el2.X else -1)
    return bvsum

Response: Calculates the BV sum of a site.


Instruction:
Write a Python 3 function that can
calculate the BV sum of a site for unordered structures.

Response:
def calculate_bv_sum_unordered(site, nn_list, scale_factor=1):
    """
    Calculates the BV sum of a site for unordered structures.

    Args:
        site:
            The site
        nn_list:
            List of nearest neighbors in the format [(nn_site, dist), ...].
        scale_factor:
            A scale factor to be applied. This is useful for scaling distance,
            esp in the case of calculation-relaxed structures which may tend
            to under (GGA) or over bind (LDA).
    """
    # If the site "site" has N partial occupations as : f_{site}_0,
    # f_{site}_1, ... f_{site}_N of elements
    # X_{site}_0, X_{site}_1, ... X_{site}_N, and each neighbors nn_i in nn
    # has N_{nn_i} partial occupations as :
    # f_{nn_i}_0, f_{nn_i}_1, ..., f_{nn_i}_{N_{nn_i}}, then the bv sum of
    # site "site" is obtained as :
    # \sum_{nn} \sum_j^N \sum_k^{N_{nn}} f_{site}_j f_{nn_i}_k vij_full
    # where vij_full is the valence bond of the fully occupied bond
    bvsum = 0
    for specie1, occu1 in site.species.items():
        el1 = Element(specie1.symbol)
        for (nn, dist) in nn_list:
            for specie2, occu2 in nn.species.items():
                el2 = Element(specie2.symbol)
                if (el1 in ELECTRONEG or el2 in ELECTRONEG) and el1 != el2:
                    r1 = BV_PARAMS[el1]["r"]
                    r2 = BV_PARAMS[el2]["r"]
                    c1 = BV_PARAMS[el1]["c"]
                    c2 = BV_PARAMS[el2]["c"]
                    R = r1 + r2 - r1 * r2 * (sqrt(c1) - sqrt(c2)) ** 2 / \
                        (c1 * r1 + c2 * r2)
                    vij = exp((R - dist * scale_factor) / 0.31)
                    bvsum += occu1 * occu2 * vij * (1 if el1.X < el2.X else -1)
    return bvsum


Instruction:
Can you write a function in Python 3 where it
adds oxidation states to a structure by site fraction.

Response:
def add_oxidation_state_by_site_fraction(structure, oxidation_states):
        """
        Add oxidation states to a structure by fractional site.

        Args:
            oxidation_states (list): List of list of oxidation states for each
                site fraction for each site.
                E.g., [[2, 4], [3], [-2], [-2], [-2]]
        """
        try:
            for i, site in enumerate(structure):
                new_sp = collections.defaultdict(float)
                for j, (el, occu) in enumerate(get_z_ordered_elmap(site
                        .species)):
                    specie = Specie(el.symbol, oxidation_states[i][j])
                    new_sp[specie] += occu
                structure[i] = new_sp
            return structure
        except IndexError:
            raise ValueError("Oxidation state of all sites must be "
                             "specified in the list.")


Instruction:
Write a Python 3 script to
return a list of valences for the structure. This currently works only for ordered structures only. Args: structure: Structure to analyze Returns: A list of valences for each site in the structure (for an ordered structure), e.g., [1, 1, -2] or a list of lists with the valences for each fractional element of each site in the structure (for an unordered structure), e.g., [[2, 4], [3], [-2], [-2], [-2]] Raises: A ValueError if the valences cannot be determined.

Response:
def get_valences(self, structure):
        """
        Returns a list of valences for the structure. This currently works only
        for ordered structures only.

        Args:
            structure: Structure to analyze

        Returns:
            A list of valences for each site in the structure (for an ordered
            structure), e.g., [1, 1, -2] or a list of lists with the
            valences for each fractional element of each site in the
            structure (for an unordered structure),
            e.g., [[2, 4], [3], [-2], [-2], [-2]]

        Raises:
            A ValueError if the valences cannot be determined.
        """
        els = [Element(el.symbol) for el in structure.composition.elements]

        if not set(els).issubset(set(BV_PARAMS.keys())):
            raise ValueError(
                "Structure contains elements not in set of BV parameters!"
            )

        # Perform symmetry determination and get sites grouped by symmetry.
        if self.symm_tol:
            finder = SpacegroupAnalyzer(structure, self.symm_tol)
            symm_structure = finder.get_symmetrized_structure()
            equi_sites = symm_structure.equivalent_sites
        else:
            equi_sites = [[site] for site in structure]

        # Sort the equivalent sites by decreasing electronegativity.
        equi_sites = sorted(equi_sites,
                            key=lambda sites: -sites[0].species
                            .average_electroneg)

        # Get a list of valences and probabilities for each symmetrically
        # distinct site.
        valences = []
        all_prob = []
        if structure.is_ordered:
            for sites in equi_sites:
                test_site = sites[0]
                nn = structure.get_neighbors(test_site, self.max_radius)
                prob = self._calc_site_probabilities(test_site, nn)
                all_prob.append(prob)
                val = list(prob.keys())
                # Sort valences in order of decreasing probability.
                val = sorted(val, key=lambda v: -prob[v])
                # Retain probabilities that are at least 1/100 of highest prob.
                valences.append(
                    list(filter(lambda v: prob[v] > 0.01 * prob[val[0]],
                                val)))
        else:
            full_all_prob = []
            for sites in equi_sites:
                test_site = sites[0]
                nn = structure.get_neighbors(test_site, self.max_radius)
                prob = self._calc_site_probabilities_unordered(test_site, nn)
                all_prob.append(prob)
                full_all_prob.extend(prob.values())
                vals = []
                for (elsp, occ) in get_z_ordered_elmap(
                        test_site.species):
                    val = list(prob[elsp.symbol].keys())
                    # Sort valences in order of decreasing probability.
                    val = sorted(val, key=lambda v: -prob[elsp.symbol][v])
                    # Retain probabilities that are at least 1/100 of highest
                    # prob.
                    vals.append(
                        list(filter(
                            lambda v: prob[elsp.symbol][v] > 0.001 * prob[
                                elsp.symbol][val[0]], val)))
                valences.append(vals)

        # make variables needed for recursion
        if structure.is_ordered:
            nsites = np.array([len(i) for i in equi_sites])
            vmin = np.array([min(i) for i in valences])
            vmax = np.array([max(i) for i in valences])

            self._n = 0
            self._best_score = 0
            self._best_vset = None

            def evaluate_assignment(v_set):
                el_oxi = collections.defaultdict(list)
                for i, sites in enumerate(equi_sites):
                    el_oxi[sites[0].specie.symbol].append(v_set[i])
                max_diff = max([max(v) - min(v) for v in el_oxi.values()])
                if max_diff > 1:
                    return
                score = functools.reduce(
                    operator.mul, [all_prob[i][v] for i, v in enumerate(v_set)])
                if score > self._best_score:
                    self._best_vset = v_set
                    self._best_score = score

            def _recurse(assigned=[]):
                # recurses to find permutations of valences based on whether a
                # charge balanced assignment can still be found
                if self._n > self.max_permutations:
                    return

                i = len(assigned)
                highest = vmax.copy()
                highest[:i] = assigned
                highest *= nsites
                highest = np.sum(highest)

                lowest = vmin.copy()
                lowest[:i] = assigned
                lowest *= nsites
                lowest = np.sum(lowest)

                if highest < 0 or lowest > 0:
                    self._n += 1
                    return

                if i == len(valences):
                    evaluate_assignment(assigned)
                    self._n += 1
                    return
                else:
                    for v in valences[i]:
                        new_assigned = list(assigned)
                        _recurse(new_assigned + [v])
        else:
            nsites = np.array([len(i) for i in equi_sites])
            tmp = []
            attrib = []
            for insite, nsite in enumerate(nsites):
                for val in valences[insite]:
                    tmp.append(nsite)
                    attrib.append(insite)
            new_nsites = np.array(tmp)
            fractions = []
            elements = []
            for sites in equi_sites:
                for sp, occu in get_z_ordered_elmap(sites[0].species):
                    elements.append(sp.symbol)
                    fractions.append(occu)
            fractions = np.array(fractions, np.float)
            new_valences = []
            for vals in valences:
                for val in vals:
                    new_valences.append(val)
            vmin = np.array([min(i) for i in new_valences], np.float)
            vmax = np.array([max(i) for i in new_valences], np.float)

            self._n = 0
            self._best_score = 0
            self._best_vset = None

            def evaluate_assignment(v_set):
                el_oxi = collections.defaultdict(list)
                jj = 0
                for i, sites in enumerate(equi_sites):
                    for specie, occu in get_z_ordered_elmap(
                            sites[0].species):
                        el_oxi[specie.symbol].append(v_set[jj])
                        jj += 1
                max_diff = max([max(v) - min(v) for v in el_oxi.values()])
                if max_diff > 2:
                    return

                score = six.moves.reduce(
                    operator.mul,
                    [all_prob[attrib[iv]][elements[iv]][vv]
                     for iv, vv in enumerate(v_set)])
                if score > self._best_score:
                    self._best_vset = v_set
                    self._best_score = score

            def _recurse(assigned=[]):
                # recurses to find permutations of valences based on whether a
                # charge balanced assignment can still be found
                if self._n > self.max_permutations:
                    return

                i = len(assigned)
                highest = vmax.copy()
                highest[:i] = assigned
                highest *= new_nsites
                highest *= fractions
                highest = np.sum(highest)

                lowest = vmin.copy()
                lowest[:i] = assigned
                lowest *= new_nsites
                lowest *= fractions
                lowest = np.sum(lowest)

                if (highest < -self.charge_neutrality_tolerance or
                        lowest > self.charge_neutrality_tolerance):
                    self._n += 1
                    return

                if i == len(new_valences):
                    evaluate_assignment(assigned)
                    self._n += 1
                    return
                else:
                    for v in new_valences[i]:
                        new_assigned = list(assigned)
                        _recurse(new_assigned + [v])

        _recurse()

        if self._best_vset:
            if structure.is_ordered:
                assigned = {}
                for val, sites in zip(self._best_vset, equi_sites):
                    for site in sites:
                        assigned[site] = val

                return [int(assigned[site]) for site in structure]
            else:
                assigned = {}
                new_best_vset = []
                for ii in range(len(equi_sites)):
                    new_best_vset.append(list())
                for ival, val in enumerate(self._best_vset):
                    new_best_vset[attrib[ival]].append(val)
                for val, sites in zip(new_best_vset, equi_sites):
                    for site in sites:
                        assigned[site] = val

                return [[int(frac_site) for frac_site in assigned[site]]
                        for site in structure]
        else:
            raise ValueError("Valences cannot be assigned!")


Instruction:
Can you implement a function in Python 3 that
gets an oxidation state decorated structure. This currently works only for ordered structures only.

Response:
def get_oxi_state_decorated_structure(self, structure):
        """
        Get an oxidation state decorated structure. This currently works only
        for ordered structures only.

        Args:
            structure: Structure to analyze

        Returns:
            A modified structure that is oxidation state decorated.

        Raises:
            ValueError if the valences cannot be determined.
        """
        s = structure.copy()
        if s.is_ordered:
            valences = self.get_valences(s)
            s.add_oxidation_state_by_site(valences)
        else:
            valences = self.get_valences(s)
            s = add_oxidation_state_by_site_fraction(s, valences)
        return s


Instruction:
How would you implement a function in Python 3 that
converts fractional coordinates of trajectory into positions

Response:
def to_positions(self):
        """
        Converts fractional coordinates of trajectory into positions
        """
        if self.coords_are_displacement:
            cumulative_displacements = np.cumsum(self.frac_coords, axis=0)
            positions = self.base_positions + cumulative_displacements
            self.frac_coords = positions
            self.coords_are_displacement = False
        return


Instruction:
Explain what the following Python 3 code does
def to_displacements(self):
        if not self.coords_are_displacement:
            displacements = np.subtract(self.frac_coords, np.roll(self.frac_coords, 1, axis=0))
            displacements[0] = np.zeros(np.shape(self.frac_coords[0]))
            # Deal with PBC
            displacements = [np.subtract(item, np.round(item)) for item in displacements]

            self.frac_coords = displacements
            self.coords_are_displacement = True
        return

Response: Converts position coordinates of trajectory into displacements between consecutive frames


Instruction:
Can you generate a brief explanation for the following Python 3 code
def extend(self, trajectory):
        if self.time_step != trajectory.time_step:
            raise ValueError('Trajectory not extended: Time steps of trajectories is incompatible')

        if len(self.species) != len(trajectory.species) and self.species != trajectory.species:
            raise ValueError('Trajectory not extended: species in trajectory do not match')

        self.to_positions()
        trajectory.to_positions()

        self.frac_coords = np.concatenate((self.frac_coords, trajectory.frac_coords), axis=0)
        self.lattice, self.constant_lattice = self._combine_attribute(self.lattice, trajectory.lattice,
                                                                      self.frac_coords.shape[0],
                                                                      trajectory.frac_coords.shape[0])
        self.site_properties = self._combine_attribute(self.site_properties, trajectory.site_properties,
                                                       self.frac_coords.shape[0], trajectory.frac_coords.shape[0])

Response: Extends this object with the contents of another trajectory.


Instruction:
Can you tell what is the following Python 3 function doing
def get_correction(self, entry):

        if not self.axis:
            list_axis_grid = np.array(entry.parameters["axis_grid"])
            list_bulk_plnr_avg_esp = np.array(entry.parameters["bulk_planar_averages"])
            list_defect_plnr_avg_esp = np.array(entry.parameters["defect_planar_averages"])
            list_axes = range(len(list_axis_grid))
        else:
            list_axes = np.array(self.axis)
            list_axis_grid, list_bulk_plnr_avg_esp, list_defect_plnr_avg_esp = [], [], []
            for ax in list_axes:
                list_axis_grid.append(np.array(entry.parameters["axis_grid"][ax]))
                list_bulk_plnr_avg_esp.append(np.array(entry.parameters["bulk_planar_averages"][ax]))
                list_defect_plnr_avg_esp.append(np.array(entry.parameters["defect_planar_averages"][ax]))

        bulk_struct = entry.defect.bulk_structure.copy()
        if "scaling_matrix" in entry.parameters.keys():
            bulk_struct.make_supercell(entry.parameters["scaling_matrix"])

        lattice = bulk_struct.lattice
        q = entry.defect.charge

        es_corr = self.perform_es_corr(lattice, entry.charge)

        pot_corr_tracker = []

        for x, pureavg, defavg, axis in zip(list_axis_grid, list_bulk_plnr_avg_esp, list_defect_plnr_avg_esp,
                                            list_axes):
            tmp_pot_corr = self.perform_pot_corr(
                x, pureavg, defavg, lattice, entry.charge, entry.site.coords, axis, widthsample=1.0)
            pot_corr_tracker.append(tmp_pot_corr)

        pot_corr = np.mean(pot_corr_tracker)

        entry.parameters["freysoldt_meta"] = dict(self.metadata)
        entry.parameters["potalign"] = pot_corr / (-q) if q else 0.

        return {"freysoldt_electrostatic": es_corr, "freysoldt_potential_alignment": pot_corr}

Response: This function returns the Freysoldt correction for a defect entry.