Ejemplo n.º 1
0
class TestPourbaixPlotter(unittest.TestCase):
    def setUp(self):
        warnings.simplefilter("ignore")

        module_dir = os.path.dirname(os.path.abspath(__file__))
        (elements, entries) = PourbaixEntryIO.from_csv(
            os.path.join(module_dir, "test_entries.csv"))
        self.num_simplices = {
            "Zn(s)": 7,
            "ZnO2(s)": 7,
            "Zn[2+]": 4,
            "ZnO2[2-]": 4,
            "ZnHO2[-]": 4
        }
        self.e_above_hull_test = {"ZnHO[+]": 0.0693, "ZnO(aq)": 0.0624}
        self.decomp_test = {
            "ZnHO[+]": {
                "ZnO(s)": 0.5,
                "Zn[2+]": 0.5
            },
            "ZnO(aq)": {
                "ZnO(s)": 1.0
            }
        }
        self.pd = PourbaixDiagram(entries)
        self.multi_data = loadfn(os.path.join(test_dir, 'multicomp_pbx.json'))
        self.plotter = PourbaixPlotter(self.pd)

    def tearDown(self):
        warnings.resetwarnings()

    def test_plot_pourbaix(self):
        # Default limits
        plt = self.plotter.get_pourbaix_plot()
        # Non-standard limits
        plt = self.plotter.get_pourbaix_plot(limits=[[-5, 4], [-2, 2]])

        # Try 3-D plot
        plot_3d = self.plotter._get_plot()
        plot_3d_unstable = self.plotter._get_plot(label_unstable=True)

        plt.close()
        plot_3d.close()
        plot_3d_unstable.close()

    def test_plot_entry_stability(self):
        entry = self.pd.all_entries[0]
        plt = self.plotter.plot_entry_stability(entry,
                                                limits=[[-2, 14], [-3, 3]])

        # binary system
        pd_binary = PourbaixDiagram(self.multi_data['binary'],
                                    comp_dict={
                                        "Ag": 0.5,
                                        "Te": 0.5
                                    })
        binary_plotter = PourbaixPlotter(pd_binary)
        test_entry = pd_binary._unprocessed_entries[0]
        plt = binary_plotter.plot_entry_stability(test_entry)
        plt.close()
Ejemplo n.º 2
0
class TestPourbaixPlotter(unittest.TestCase):
    def setUp(self):
        module_dir = os.path.dirname(os.path.abspath(__file__))
        (elements, entries) = PourbaixEntryIO.from_csv(
            os.path.join(module_dir, "test_entries.csv"))
        self.num_simplices = {
            "Zn(s)": 7,
            "ZnO2(s)": 7,
            "Zn[2+]": 4,
            "ZnO2[2-]": 4,
            "ZnHO2[-]": 4
        }
        self.e_above_hull_test = {"ZnHO[+]": 0.0693, "ZnO(aq)": 0.0624}
        self.decomp_test = {
            "ZnHO[+]": {
                "ZnO(s)": 0.5,
                "Zn[2+]": 0.5
            },
            "ZnO(aq)": {
                "ZnO(s)": 1.0
            }
        }
        self.pd = PourbaixDiagram(entries)
        self.plotter = PourbaixPlotter(self.pd)

    def test_plot_pourbaix(self):
        plt = self.plotter.get_pourbaix_plot(limits=[[-2, 14], [-3, 3]])

    def test_get_entry_stability(self):
        entry = self.pd.all_entries[0]
        plt = self.plotter.plot_entry_stability(entry,
                                                limits=[[-2, 14], [-3, 3]])
Ejemplo n.º 3
0
class TestPourbaixPlotter(unittest.TestCase):

    def setUp(self):
        warnings.simplefilter("ignore")

        module_dir = os.path.dirname(os.path.abspath(__file__))
        (elements, entries) = PourbaixEntryIO.from_csv(os.path.join(module_dir,
                                                    "test_entries.csv"))
        self.num_simplices = {"Zn(s)": 7, "ZnO2(s)": 7, "Zn[2+]": 4, "ZnO2[2-]": 4, "ZnHO2[-]": 4}
        self.e_above_hull_test = {"ZnHO[+]": 0.0693, "ZnO(aq)": 0.0624}
        self.decomp_test = {"ZnHO[+]": {"ZnO(s)": 0.5, "Zn[2+]": 0.5}, "ZnO(aq)": {"ZnO(s)": 1.0}}
        self.pd = PourbaixDiagram(entries)
        self.multi_data = loadfn(os.path.join(test_dir, 'multicomp_pbx.json'))
        self.plotter = PourbaixPlotter(self.pd)

    def tearDown(self):
        warnings.resetwarnings()

    def test_plot_pourbaix(self):
        # Default limits
        plt = self.plotter.get_pourbaix_plot()
        # Non-standard limits
        plt = self.plotter.get_pourbaix_plot(limits=[[-5, 4], [-2, 2]])
        
        # Try 3-D plot
        plot_3d = self.plotter._get_plot()
        plot_3d_unstable = self.plotter._get_plot(label_unstable=True)

        plt.close()
        plot_3d.close()
        plot_3d_unstable.close()

    def test_plot_entry_stability(self):
        entry = self.pd.all_entries[0]
        plt = self.plotter.plot_entry_stability(entry, limits=[[-2, 14], [-3, 3]])

        # binary system
        pd_binary = PourbaixDiagram(self.multi_data['binary'],
                                    comp_dict = {"Ag": 0.5, "Te": 0.5})
        binary_plotter = PourbaixPlotter(pd_binary)
        test_entry = pd_binary._unprocessed_entries[0]
        plt = binary_plotter.plot_entry_stability(test_entry)
        plt.close()
Ejemplo n.º 4
0
def plot_pourbaix_diagram(metastability=0.0,
                          ion_concentration=1e-6,
                          fmt='pdf'):
    """
    Creates a Pourbaix diagram for the material in the cwd.

    Args:
        metastability (float): desired metastable tolerance energy
            (meV/atom). <~50 is generally a sensible range to use.
        ion_concentration (float): in mol/kg. Sensible values are
            generally between 1e-8 and 1.
        fmt (str): matplotlib format style. Check the matplotlib
            docs for options.
    """

    # Create a ComputedEntry object for the 2D material.
    composition = Structure.from_file('POSCAR').composition
    energy = Vasprun('vasprun.xml').final_energy

    cmpd = ComputedEntry(composition, energy)

    # Define the chemsys that describes the 2D compound.
    chemsys = ['O', 'H'] + [
        elt.symbol
        for elt in composition.elements if elt.symbol not in ['O', 'H']
    ]

    # Pick out the ions pertaining to the 2D compound.
    ion_dict = dict()
    for elt in chemsys:
        if elt not in ['O', 'H'] and ION_FORMATION_ENERGIES[elt]:
            ion_dict.update(ION_FORMATION_ENERGIES[elt])

    elements = [Element(elt) for elt in chemsys if elt not in ['O', 'H']]

    # Add "correction" for metastability
    cmpd.correction -= float(cmpd.composition.num_atoms)\
        * float(metastability) / 1000.0

    # Calculate formation energy of the compound from its end
    # members
    form_energy = cmpd.energy
    for elt in composition.as_dict():
        form_energy -= CHEMICAL_POTENTIALS[elt] * cmpd.composition[elt]

    # Convert the compound entry to a pourbaix entry.
    # Default concentration for solid entries = 1
    pbx_cmpd = PourbaixEntry(cmpd)
    pbx_cmpd.g0_replace(form_energy)
    pbx_cmpd.reduced_entry()

    # Add corrected ionic entries to the pourbaix diagram
    # dft corrections for experimental ionic energies:
    # Persson et.al PHYSICAL REVIEW B 85, 235438 (2012)
    pbx_ion_entries = list()

    # Get PourbaixEntry corresponding to each ion.
    # Default concentration for ionic entries = 1e-6
    # ion_energy = ion_exp_energy + ion_correction * factor
    # where factor = fraction of element el in the ionic entry
    # compared to the reference entry
    for elt in elements:
        for key in ion_dict:
            comp = Ion.from_formula(key)
            if comp.composition[elt] != 0:
                factor = comp.composition[elt]
                energy = ion_dict[key]
                pbx_entry_ion = PourbaixEntry(IonEntry(comp, energy))
                pbx_entry_ion.correction = (ION_CORRECTIONS[elt.symbol] *
                                            factor)
                pbx_entry_ion.conc = ion_concentration
                pbx_entry_ion.name = key
                pbx_ion_entries.append(pbx_entry_ion)

    # Generate and plot Pourbaix diagram
    # Each bulk solid/ion has a free energy g of the form:
    # g = g0_ref + 0.0591 * log10(conc) - nO * mu_H2O +
    # (nH - 2nO) * pH + phi * (-nH + 2nO + q)

    all_entries = [pbx_cmpd] + pbx_ion_entries

    pourbaix = PourbaixDiagram(all_entries)

    # Analysis features
    # panalyzer = PourbaixAnalyzer(pourbaix)
    # instability = panalyzer.get_e_above_hull(pbx_cmpd)

    plotter = PourbaixPlotter(pourbaix)
    plot = plotter.get_pourbaix_plot(limits=[[0, 14], [-2, 2]],
                                     label_domains=True)
    fig = plot.gcf()
    ax1 = fig.gca()

    # Add coloring to highlight the stability region for the 2D
    # material, if one exists.
    stable_entries = plotter.pourbaix_plot_data(limits=[[0, 14], [-2, 2]])[0]

    for entry in stable_entries:
        if entry == pbx_cmpd:
            col = plt.cm.Blues(0)
        else:
            col = plt.cm.rainbow(
                float(ION_COLORS[entry.composition.reduced_formula]))

        vertices = plotter.domain_vertices(entry)
        patch = Polygon(vertices, closed=True, fill=True, color=col)
        ax1.add_patch(patch)

    fig.set_size_inches((11.5, 9))
    plot.tight_layout(pad=1.09)

    # Save plot
    if metastability:
        plot.suptitle('Metastable Tolerance ='
                      ' {} meV/atom'.format(metastability),
                      fontsize=20)
        plot.savefig('{}_{}.{}'.format(composition.reduced_formula,
                                       ion_concentration, fmt),
                     transparent=True)
    else:
        plot.savefig('{}_{}.{}'.format(composition.reduced_formula,
                                       ion_concentration, fmt),
                     transparent=True)

    plot.close()
Ejemplo n.º 5
0
def plot_pourbaix_diagram(metastability=0.0, ion_concentration=1e-6, fmt='pdf'):
    """
    Creates a Pourbaix diagram for the material in the cwd.

    Args:
        metastability (float): desired metastable tolerance energy
            (meV/atom). <~50 is generally a sensible range to use.
        ion_concentration (float): in mol/kg. Sensible values are
            generally between 1e-8 and 1.
        fmt (str): matplotlib format style. Check the matplotlib
            docs for options.
    """

    # Create a ComputedEntry object for the 2D material.
    composition = Structure.from_file('POSCAR').composition
    energy = Vasprun('vasprun.xml').final_energy

    cmpd = ComputedEntry(composition, energy)

    # Define the chemsys that describes the 2D compound.
    chemsys = ['O', 'H'] + [elt.symbol for elt in composition.elements
                            if elt.symbol not in ['O', 'H']]

    # Experimental ionic energies
    # See ions.yaml for ion formation energies and references.
    exp_dict = ION_DATA['ExpFormEnergy']
    ion_correction = ION_DATA['IonCorrection']

    # Pick out the ions pertaining to the 2D compound.
    ion_dict = dict()
    for elt in chemsys:
        if elt not in ['O', 'H'] and exp_dict[elt]:
            ion_dict.update(exp_dict[elt])

    elements = [Element(elt) for elt in chemsys if elt not in ['O', 'H']]

    # Add "correction" for metastability
    cmpd.correction -= float(cmpd.composition.num_atoms)\
        * float(metastability) / 1000.0

    # Calculate formation energy of the compound from its end
    # members
    form_energy = cmpd.energy
    for elt in composition.as_dict():
        form_energy -= END_MEMBERS[elt] * cmpd.composition[elt]

    # Convert the compound entry to a pourbaix entry.
    # Default concentration for solid entries = 1
    pbx_cmpd = PourbaixEntry(cmpd)
    pbx_cmpd.g0_replace(form_energy)
    pbx_cmpd.reduced_entry()

    # Add corrected ionic entries to the pourbaix diagram
    # dft corrections for experimental ionic energies:
    # Persson et.al PHYSICAL REVIEW B 85, 235438 (2012)
    pbx_ion_entries = list()

    # Get PourbaixEntry corresponding to each ion.
    # Default concentration for ionic entries = 1e-6
    # ion_energy = ion_exp_energy + ion_correction * factor
    # where factor = fraction of element el in the ionic entry
    # compared to the reference entry
    for elt in elements:
        for key in ion_dict:
            comp = Ion.from_formula(key)
            if comp.composition[elt] != 0:
                factor = comp.composition[elt]
                energy = ion_dict[key]
                pbx_entry_ion = PourbaixEntry(IonEntry(comp, energy))
                pbx_entry_ion.correction = ion_correction[elt.symbol]\
                    * factor
                pbx_entry_ion.conc = ion_concentration
                pbx_entry_ion.name = key
                pbx_ion_entries.append(pbx_entry_ion)

    # Generate and plot Pourbaix diagram
    # Each bulk solid/ion has a free energy g of the form:
    # g = g0_ref + 0.0591 * log10(conc) - nO * mu_H2O +
    # (nH - 2nO) * pH + phi * (-nH + 2nO + q)

    all_entries = [pbx_cmpd] + pbx_ion_entries

    pourbaix = PourbaixDiagram(all_entries)

    # Analysis features
    panalyzer = PourbaixAnalyzer(pourbaix)
#    instability = panalyzer.get_e_above_hull(pbx_cmpd)

    plotter = PourbaixPlotter(pourbaix)
    plot = plotter.get_pourbaix_plot(limits=[[0, 14], [-2, 2]],
                                     label_domains=True)
    fig = plot.gcf()
    ax1 = fig.gca()

    # Add coloring to highlight the stability region for the 2D
    # material, if one exists.
    stable_entries = plotter.pourbaix_plot_data(
        limits=[[0, 14], [-2, 2]])[0]

    for entry in stable_entries:
        if entry == pbx_cmpd:
            col = plt.cm.Blues(0)
        else:
            col = plt.cm.rainbow(float(
                ION_COLORS[entry.composition.reduced_formula]))

        vertices = plotter.domain_vertices(entry)
        patch = Polygon(vertices, closed=True, fill=True, color=col)
        ax1.add_patch(patch)

    fig.set_size_inches((11.5, 9))
    plot.tight_layout(pad=1.09)

    # Save plot
    if metastability:
        plot.suptitle('Metastable Tolerance ='
                      ' {} meV/atom'.format(metastability),
                      fontsize=20)
        plot.savefig('{}_{}.{}'.format(
            composition.reduced_formula, ion_concentration, fmt),
            transparent=True)
    else:
        plot.savefig('{}_{}.{}'.format(composition.reduced_formula,
                                        ion_concentration, fmt),
                     transparent=True)

    plot.close()