Ejemplo n.º 1
0
 def test_tet_coord(self):
     coord = [0.5, 0.5, 0.5]
     coord = tet_coord(coord)
     self.assertTrue(np.allclose(coord, [1.0, 0.57735027, 0.40824829]))
Ejemplo n.º 2
0
    def present(self,
                df=None,
                new_result_ids=None,
                all_result_ids=None,
                filename=None,
                save_hull_distance=False,
                finalize=False):
        """
        Generate plots of convex hulls for each of the runs

        Args:
            df (DataFrame): dataframe with formation energies, compositions, ids
            new_result_ids ([]): list of new result ids (i. e. indexes
                in the updated dataframe)
            all_result_ids ([]): list of all result ids associated
                with the current run
            filename (str): filename to output, if None, no file output
                is produced

        Returns:
            (pyplot): plotter instance
        """
        df = df if df is not None else self.df
        new_result_ids = new_result_ids if new_result_ids is not None \
            else self.new_result_ids
        all_result_ids = all_result_ids if all_result_ids is not None \
            else self.all_result_ids

        # TODO: consolidate duplicated code here
        # Generate all entries
        comps = df.loc[all_result_ids]['Composition'].dropna()
        system_elements = []
        for comp in comps:
            system_elements += list(Composition(comp).as_dict().keys())
        elems = set(system_elements)
        if len(elems) > 4:
            warnings.warn(
                "Number of elements too high for phase diagram plotting")
            return None
        ind_to_include = []
        for ind in df.index:
            if set(Composition(
                    df.loc[ind]['Composition']).as_dict().keys()).issubset(
                        elems):
                ind_to_include.append(ind)
        _df = df.loc[ind_to_include]

        # Create computed entry column
        _df['entry'] = [
            ComputedEntry(
                Composition(row['Composition']),
                row['delta_e'] * Composition(
                    row['Composition']).num_atoms,  # un-normalize the energy
                entry_id=index) for index, row in _df.iterrows()
        ]
        # Partition ids into sets of prior to CAMD run, from CAMD but prior to
        # current iteration, and new ids
        ids_prior_to_camd = list(set(_df.index) - set(all_result_ids))
        ids_prior_to_run = list(set(all_result_ids) - set(new_result_ids))

        # Create phase diagram based on everything prior to current run
        entries = list(_df.loc[ids_prior_to_run + ids_prior_to_camd]['entry'])
        # Filter for nans by checking if it's a computed entry
        entries = [
            entry for entry in entries if isinstance(entry, ComputedEntry)
        ]
        pg_elements = [Element(el) for el in sorted(elems)]
        pd = PhaseDiagram(entries, elements=pg_elements)
        plotkwargs = {
            "markerfacecolor": "white",
            "markersize": 7,
            "linewidth": 2,
        }
        if finalize:
            plotkwargs.update({'linestyle': '--'})
        else:
            plotkwargs.update({'linestyle': '-'})
        plotter = PDPlotter(pd, **plotkwargs)

        getplotkwargs = {"label_stable": False} if finalize else {}
        plot = plotter.get_plot(**getplotkwargs)
        # Get valid results
        valid_results = [
            new_result_id for new_result_id in new_result_ids
            if new_result_id in _df.index
        ]

        if finalize:
            # If finalize, we'll reset pd to all entries at this point
            # to measure stabilities wrt. the ultimate hull.
            pd = PhaseDiagram(_df['entry'].values, elements=pg_elements)
            plotter = PDPlotter(
                pd, **{
                    "markersize": 0,
                    "linestyle": "-",
                    "linewidth": 2
                })
            plot = plotter.get_plot(plt=plot)

        for entry in _df['entry'][valid_results]:
            decomp, e_hull = pd.get_decomp_and_e_above_hull(
                entry, allow_negative=True)
            if e_hull < self.hull_distance:
                color = 'g'
                marker = 'o'
                markeredgewidth = 1
            else:
                color = 'r'
                marker = 'x'
                markeredgewidth = 1

            # Get coords
            coords = [
                entry.composition.get_atomic_fraction(el) for el in pd.elements
            ][1:]
            if pd.dim == 2:
                coords = coords + [pd.get_form_energy_per_atom(entry)]
            if pd.dim == 3:
                coords = triangular_coord(coords)
            elif pd.dim == 4:
                coords = tet_coord(coords)
            plot.plot(*coords,
                      marker=marker,
                      markeredgecolor=color,
                      markerfacecolor="None",
                      markersize=11,
                      markeredgewidth=markeredgewidth)

        if filename is not None:
            plot.savefig(filename, dpi=70)
        plot.close()

        if filename is not None and save_hull_distance:
            if self.stabilities is None:
                print("ERROR: No stability information in analyzer.")
                return None
            with open(filename.split(".")[0] + '.json', 'w') as f:
                json.dump(self.stabilities, f)
Ejemplo n.º 3
0
    def plot_hull(self, df, new_result_ids, filename=None, finalize=False):
        """
        Generate plots of convex hulls for each of the runs

        Args:
            df (DataFrame): dataframe with formation energies and formulas
            new_result_ids ([]): list of new result ids (i. e. indexes
                in the updated dataframe)
            filename (str): filename to output, if None, no file output
                is produced
            finalize (bool): flag indicating whether to include all new results

        Returns:
            (pyplot): plotter instance
        """
        # Generate all entries
        total_comp = Composition(df['Composition'].sum())
        if len(total_comp) > 4:
            warnings.warn(
                "Number of elements too high for phase diagram plotting")
            return None
        filtered = filter_dataframe_by_composition(df, total_comp)
        filtered = filtered[['delta_e', 'Composition']]
        filtered = filtered.dropna()

        # Create computed entry column with un-normalized energies
        filtered["entry"] = [
            ComputedEntry(
                Composition(row["Composition"]),
                row["delta_e"] * Composition(row["Composition"]).num_atoms,
                entry_id=index,
            ) for index, row in filtered.iterrows()
        ]

        ids_prior_to_run = list(set(filtered.index) - set(new_result_ids))
        if not ids_prior_to_run:
            warnings.warn(
                "No prior data, prior phase diagram cannot be constructed")
            return None

        # Create phase diagram based on everything prior to current run
        entries = filtered.loc[ids_prior_to_run]["entry"].dropna()

        # Filter for nans by checking if it's a computed entry
        pg_elements = sorted(total_comp.keys())
        pd = PhaseDiagram(entries, elements=pg_elements)
        plotkwargs = {
            "markerfacecolor": "white",
            "markersize": 7,
            "linewidth": 2,
        }
        if finalize:
            plotkwargs.update({"linestyle": "--"})
        else:
            plotkwargs.update({"linestyle": "-"})
        plotter = PDPlotter(pd, backend='matplotlib', **plotkwargs)

        getplotkwargs = {"label_stable": False} if finalize else {}
        plot = plotter.get_plot(**getplotkwargs)

        # Get valid results
        valid_results = [
            new_result_id for new_result_id in new_result_ids
            if new_result_id in filtered.index
        ]

        if finalize:
            # If finalize, we'll reset pd to all entries at this point to
            # measure stabilities wrt. the ultimate hull.
            pd = PhaseDiagram(filtered["entry"].values, elements=pg_elements)
            plotter = PDPlotter(pd,
                                backend="matplotlib",
                                **{
                                    "markersize": 0,
                                    "linestyle": "-",
                                    "linewidth": 2
                                })
            plot = plotter.get_plot(plt=plot)

        for entry in filtered["entry"][valid_results]:
            decomp, e_hull = pd.get_decomp_and_e_above_hull(
                entry, allow_negative=True)
            if e_hull < self.hull_distance:
                color = "g"
                marker = "o"
                markeredgewidth = 1
            else:
                color = "r"
                marker = "x"
                markeredgewidth = 1

            # Get coords
            coords = [
                entry.composition.get_atomic_fraction(el) for el in pd.elements
            ][1:]
            if pd.dim == 2:
                coords = coords + [pd.get_form_energy_per_atom(entry)]
            if pd.dim == 3:
                coords = triangular_coord(coords)
            elif pd.dim == 4:
                coords = tet_coord(coords)
            plot.plot(*coords,
                      marker=marker,
                      markeredgecolor=color,
                      markerfacecolor="None",
                      markersize=11,
                      markeredgewidth=markeredgewidth)

        if filename is not None:
            plot.savefig(filename, dpi=70)
        plot.close()
Ejemplo n.º 4
0
def plot_quaternary_pd(pd):
    # different length but not at all
    qhull_data = pd.qhull_data
    qhull_data = np.delete(qhull_data, -1, axis=0)

    qhull_cord = np.vstack([tet_coord(qhull_data[i, 0:3])
                            for i in range(qhull_data.shape[0])])
    facet_vertices = pd.facets
    qhull_stable = [qhull_cord[each] for each in facet_vertices]

    data = []

    # plot dash segment lines between nodes
    line_list = []
    for qhull in qhull_stable:
        polyhedron = qhull[:, 0:3]
        hull = ConvexHull(polyhedron)
        for simplex in hull.simplices:
            facet = polyhedron[simplex]
            lines = list(combinations(facet, 2))
            lines = [np.array(l) for l in lines]
            for line in lines:
                duplicate_boolean = [
                    (line.round(3) == l.round(3)).all() for l in line_list]
                if not True in duplicate_boolean:
                    line_list.append(line)

    for line in line_list:
        convex_lines = plotly_lines(line, 'dash')
        data.append(convex_lines)

    #######################################################
    # If need to draw certain faces in solid lines, like the faces on the front,
    # ddd coordinations of the facet here.
    # note to comment them out at the first run.
    #######################################################
    facet_front = [[[0.5, 0.8660254, 0.],
                    [0.83333333, 0.28867513, 0.],
                    [0., 0., 0]],
                   [[0.83333333, 0.28867513, 0.],
                    [1., 0., 0],
                    [0., 0., 0]]]

    for facet in facet_front:
        lines_front = list(combinations(facet, 2))
        lines_front = [np.array(l) for l in lines_front]
        for line in lines_front:
            convex_lines = plotly_lines(line, 'solid')
            data.append(convex_lines)
    #######################################################

    facet_element = tieline_phases(pd, 'Li')
    qhull_element = np.array([qhull_cord[each] for each in facet_element])
    for index, qhull in enumerate(qhull_element):
        polyhedron = qhull[:, 0:3]
        color = palette.Plotly[index % 10]
        convex_polyhedon = plotly_polyhedron(polyhedron, color=color)
        data.append(convex_polyhedon)

    # add node points
    nodes_index = np.array(facet_vertices).flatten()
    nodes_index = np.unique(nodes_index)
    # nodes_name = np.array([entries[each].name for each in nodes_index])
    nodes_array = np.vstack([qhull_cord[each] for each in nodes_index])

    scatter_vertices = dict(
        mode="markers",
        name='nodes',
        type="scatter3d",
        x=nodes_array[:, 0], y=nodes_array[:, 1], z=nodes_array[:, 2],
        # marker = dict(size=5, color="rgb(106, 90, 205)")
        marker=dict(size=6, color="rgb(50,50,50)")
    )
    data.append(scatter_vertices)

    layout = dict(
        # title = '<b>Quaternary Phase Diagram</b>',
        title_x=0.5,
        scene=dict(xaxis=dict(zeroline=False, showticklabels=False, showgrid=False, showline=False, title={'text': ''}, visible=False),
                   yaxis=dict(zeroline=False, showticklabels=False, showgrid=False,
                              showline=False, title={'text': ''}, visible=False),
                   # visible=False, showaxeslabels=False,
                   zaxis=dict(zeroline=False, showticklabels=False, showgrid=False,
                              showline=False, title={'text': ''}, visible=False),
                   camera=dict(eye=dict(x=2.0, y=1.0, z=0.5)),
                   ),
        showlegend=False,
        # width = 1000,
        # height = 1000,
        autosize=True
        # annotations = make_annotations(nodes_array, v_label),
    )

    fig = dict(data=data, layout=layout)
    return fig