示例#1
0
    def get_pourbaix_entries(self, chemsys):
        """
        A helper function to get all entries necessary to generate
        a pourbaix diagram from the rest interface.

        Args:
            chemsys ([str]): A list of elements comprising the chemical
                system, e.g. ['Li', 'Fe']
        """
        from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry
        from pymatgen.analysis.phase_diagram import PhaseDiagram
        from pymatgen.core.ion import Ion
        from pymatgen.entries.compatibility import\
            MaterialsProjectAqueousCompatibility

        chemsys = list(set(chemsys + ['O', 'H']))
        entries = self.get_entries_in_chemsys(chemsys,
                                              property_data=['e_above_hull'],
                                              compatible_only=False)
        compat = MaterialsProjectAqueousCompatibility("Advanced")
        entries = compat.process_entries(entries)
        solid_pd = PhaseDiagram(
            entries)  # Need this to get ion formation energy
        url = '/pourbaix_diagram/reference_data/' + '-'.join(chemsys)
        ion_data = self._make_request(url)

        pbx_entries = []
        for entry in entries:
            if not set(entry.composition.elements)\
                    <= {Element('H'), Element('O')}:
                pbx_entry = PourbaixEntry(entry)
                pbx_entry.g0_replace(solid_pd.get_form_energy(entry))
                pbx_entry.reduced_entry()
                pbx_entries.append(pbx_entry)

        # position the ion energies relative to most stable reference state
        for n, i_d in enumerate(ion_data):
            ion_entry = IonEntry(Ion.from_formula(i_d['Name']), i_d['Energy'])
            refs = [
                e for e in entries
                if e.composition.reduced_formula == i_d['Reference Solid']
            ]
            if not refs:
                raise ValueError("Reference solid not contained in entry list")
            stable_ref = sorted(refs, key=lambda x: x.data['e_above_hull'])[0]
            rf = stable_ref.composition.get_reduced_composition_and_factor()[1]
            solid_diff = solid_pd.get_form_energy(stable_ref)\
                         - i_d['Reference solid energy'] * rf
            elt = i_d['Major_Elements'][0]
            correction_factor = ion_entry.ion.composition[elt]\
                                / stable_ref.composition[elt]
            correction = solid_diff * correction_factor
            pbx_entries.append(
                PourbaixEntry(ion_entry, correction, 'ion-{}'.format(n)))
        return pbx_entries
示例#2
0
    def get_pourbaix_entries(self, chemsys):
        """
        A helper function to get all entries necessary to generate
        a pourbaix diagram from the rest interface.

        Args:
            chemsys ([str]): A list of elements comprising the chemical
                system, e.g. ['Li', 'Fe']
        """
        from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry
        from pymatgen.analysis.phase_diagram import PhaseDiagram
        from pymatgen.core.ion import Ion
        from pymatgen.entries.compatibility import\
            MaterialsProjectAqueousCompatibility

        chemsys = list(set(chemsys + ['O', 'H']))
        entries = self.get_entries_in_chemsys(
            chemsys, property_data=['e_above_hull'], compatible_only=False)
        compat = MaterialsProjectAqueousCompatibility("Advanced")
        entries = compat.process_entries(entries)
        solid_pd = PhaseDiagram(entries) # Need this to get ion formation energy
        url = '/pourbaix_diagram/reference_data/' + '-'.join(chemsys)
        ion_data = self._make_request(url)

        pbx_entries = []
        for entry in entries:
            if not set(entry.composition.elements)\
                    <= {Element('H'), Element('O')}:
                pbx_entry = PourbaixEntry(entry)
                pbx_entry.g0_replace(solid_pd.get_form_energy(entry))
                pbx_entry.reduced_entry()
                pbx_entries.append(pbx_entry)

        # position the ion energies relative to most stable reference state
        for n, i_d in enumerate(ion_data):
            ion_entry = IonEntry(Ion.from_formula(i_d['Name']), i_d['Energy'])
            refs = [e for e in entries
                    if e.composition.reduced_formula == i_d['Reference Solid']]
            if not refs:
                raise ValueError("Reference solid not contained in entry list")
            stable_ref = sorted(refs, key=lambda x: x.data['e_above_hull'])[0]
            rf = stable_ref.composition.get_reduced_composition_and_factor()[1]
            solid_diff = solid_pd.get_form_energy(stable_ref)\
                         - i_d['Reference solid energy'] * rf
            elt = i_d['Major_Elements'][0]
            correction_factor = ion_entry.ion.composition[elt]\
                                / stable_ref.composition[elt]
            correction = solid_diff * correction_factor
            pbx_entries.append(PourbaixEntry(ion_entry, correction,
                                             'ion-{}'.format(n)))
        return pbx_entries
示例#3
0
def form_e(stable_solids_minus_h2o, entries_aqcorr, gas_gibbs=True):
    """
    Calculate the formation energy for the entries in stable_solids_minus_h2o
    Reduce by stoicheometric factor if applicable (ex. Fe4O4)

    Args:
        stable_solids_minus_h2o: list of stable solids without O2, H2O, H2, and
    H2O2 (from stable_entr)
        entries_aqcorr: entries list before being modified by stable_entr
    """
    #| -  form_e

    #| -  Imported Modules
    from pymatgen.analysis.pourbaix.entry import PourbaixEntry
    from pymatgen.phasediagram.maker import PhaseDiagram
    from entry_methods import base_atom
    from energy_scheme import ref_atoms_dict
    #__|

    ref_atom_energies = ref_atoms_dict()
    e_o = ref_atom_energies['e_o']
    e_h = ref_atom_energies['e_h']

    pd = PhaseDiagram(entries_aqcorr)

    base_at = base_atom(stable_solids_minus_h2o)
    d = {}
    for i in stable_solids_minus_h2o:
        if i.name in base_at:
            d[i.name] = i.energy_per_atom

    def form_energy(entry, solid_ref_energy_dict, gas_gibbs=True):
        """
        Calculates the formation energy of an entry relative to the VASP
        energies of the reference atoms. Gibbs/entropy corrections for the gas
        phase are optionable

        Args:
            entry: Entry whose formation energy will be calculated
            solid_ref_energy_dict: Dictionary of reference atom energies
            gas_gibbs: Whether the gas phase reference atoms will have an
            entropic correction
        """
        if gas_gibbs==True:
            ref_dict = {}
            ref_dict['O'] = e_o-0.3167
            ref_dict['H'] = e_h-0.36218
        elif gas_gibbs==False:
            ref_dict = {}
            ref_dict['O'] = e_o
            ref_dict['H'] = e_h

        z = ref_dict.copy()
        z.update(solid_ref_energy_dict)
        ref_dict = z

        elem_dict = entry.composition.get_el_amt_dict()
        entry_e = entry.energy

        for elem in entry.composition.elements:
            elem_num = elem_dict[elem.symbol]
            entry_e = entry_e - elem_num*ref_dict[elem.symbol]
        return entry_e

    pbx_solid_entries = []
    for entry in stable_solids_minus_h2o:
        pbx_entry = PourbaixEntry(entry)
        pbx_entry.g0_replace(form_energy(entry, d, gas_gibbs=gas_gibbs)) #Replace E with form E relative to ref elements
        # pbx_entry.g0_replace(pd.get_form_energy(entry)) #Replace E with form E relative to ref elements
        pbx_entry.reduced_entry() #Reduces parameters by stoich factor (ex. Li2O2 -> LiO)
        pbx_solid_entries.append(pbx_entry)

    return pbx_solid_entries
示例#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()
示例#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']]

    # 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

    total = sum([composition[el] for el in elements])
    comp_dict = {el.symbol: composition[el]/total for el in elements}
    pourbaix_diagram = PourbaixDiagram(all_entries, comp_dict=comp_dict)

    plotter = PourbaixPlotter(pourbaix_diagram)

    # Plotting details...
    font = "serif"
    fig = plt.figure(figsize=(14, 9))
    ax1 = fig.gca()
    ax1.set_xlim([0, 14])
    ax1.set_xticklabels([int(t) for t in ax1.get_xticks()], fontname=font,
                        fontsize=18)
    ax1.set_ylim(-2, 2)
    ax1.set_yticklabels(ax1.get_yticks(), fontname=font, fontsize=18)
    ax1.set_xlabel("pH", fontname=font, fontsize=18)
    ax1.set_ylabel("Potential vs. SHE (V)", fontname=font, fontsize=18)

    # Outline water's stability range.
    ax1.plot([0, 14], [0, -0.829], color="gray", linestyle="--", alpha=0.7,
             linewidth=2)
    ax1.plot([0, 14], [1.229, 0.401], color="gray", linestyle="--", alpha=0.7,
             linewidth=2)


    stable_entries = plotter.pourbaix_plot_data(
        limits=[[0, 14], [-2, 2]])[0]

    # Add coloring.
    colors = sb.color_palette("Set2", len(stable_entries))

    i = 0
    for entry in stable_entries:
        col = colors[i]
        i += 1
        vertices = plotter.domain_vertices(entry)
        center_x = sum([v[0] for v in vertices])/len(vertices)
        center_y = sum([v[1] for v in vertices])/len(vertices)
        patch = Polygon(vertices, closed=True, fill=True, facecolor=col,
                        linewidth=2, edgecolor="w")
        ax1.text(center_x, center_y, plotter.print_name(entry),
                 verticalalignment="center", horizontalalignment="center",
                 fontname=font, fontsize=18)
        ax1.add_patch(patch)

    plt.savefig("pourbaix.{}".format(fmt))

    plt.close()
示例#6
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()