Example #1
0
def input_handling(args):
    comp1 = Composition(args.composition_1)
    comp2 = Composition(args.composition_2)
    entry1 = VirtualEntry.from_composition(comp1)
    entry2 = VirtualEntry.from_composition(comp2)
    entry1.stabilize()
    entry2.stabilize()
    entry1.energy_correction(args.e1)
    entry2.energy_correction(args.e2)
    return entry1, entry2
def get_mix_entry(mix_dict):
    """
    Mixing PDEntry or GrandPotEntry for the binary search algorithm.
    """
    entry1, entry2 = mix_dict.keys()
    x1, x2 = mix_dict[entry1], mix_dict[entry2]
    if type(entry1) == GrandPotPDEntry:
        mid_ori_entry = VirtualEntry.from_mixing({
            entry1.original_entry: x1,
            entry2.original_entry: x2
        })
        return GrandPotPDEntry(mid_ori_entry, entry1.chempots)
    else:
        return VirtualEntry.from_mixing({entry1: x1, entry2: x2})
Example #3
0
def get_phase_equilibria_from_composition(args):
    """
    Provides the phase equilibria of a phase with given composition
    """
    comp = Composition(args.composition)
    entry = VirtualEntry.from_composition(comp)
    print(entry.get_printable_PE_data_in_pd())
    return 0
def get_full_evolution_profile(pd, entry1, entry2, x1, x2):
    """
    This function is used to solve the transition points along a path on convex hull.
    The essence is to use binary search, which is more accurate and faster than brutal force screening
    This is a recursive function.
    :param pd: PhaseDiagram of GrandPotentialPhaseDiagram
    :param entry1 & entry2: mixing entry1/entry2, PDEntry for pd_mixing, GrandPotEntry for gppd_mixing
    :param x1 & x2: The mixing ratio range for binary search.
    :return: An uncleaned but complete profile with all transition points.
    """
    evolution_profile = {}
    entry_left = get_mix_entry({entry1: x1, entry2: 1 - x1})
    entry_right = get_mix_entry({entry1: x2, entry2: 1 - x2})
    (decomp1, h1) = pd.get_decomp_and_e_above_hull(entry_left)
    (decomp2, h2) = pd.get_decomp_and_e_above_hull(entry_right)
    decomp1 = set(decomp1.keys())
    decomp2 = set(decomp2.keys())
    evolution_profile[x1] = (decomp1, h1)
    evolution_profile[x2] = (decomp2, h2)

    if decomp1 == decomp2:
        return evolution_profile

    intersect = decomp1 & decomp2
    if len(intersect) > 0:
        # This is try to catch a single transition point
        try:
            rxn = ComputedReaction([entry_left, entry_right], list(intersect))
            if not {entry_left, entry_right} < set(rxn.all_entries):
                return evolution_profile

            c1 = rxn.coeffs[rxn.all_entries.index(entry_left)]
            c2 = rxn.coeffs[rxn.all_entries.index(
                entry_right
            )]  # I know this is tedious but this is the only way I found that works..
            x = (c1 * x1 + c2 * x2) / (c1 + c2)
            if c1 * c2 == 0:
                return evolution_profile
            entry_mid = VirtualEntry.from_mixing({
                entry_left: c1 / (c1 + c2),
                entry_right: c2 / (c1 + c2)
            })
            h_mid = pd.get_decomp_and_e_above_hull(entry_mid)[1]
            evolution_profile[x] = (intersect, h_mid)
            return evolution_profile
        except ReactionError:
            pass

    x_mid = (x1 + x2) / 2.0
    entry_mid = get_mix_entry({entry1: 0.5, entry2: 0.5})
    (decomp_mid, h_mid) = pd.get_decomp_and_e_above_hull(entry_mid)
    decomp_mid = set(decomp_mid.keys())
    evolution_profile[x_mid] = (decomp_mid, h_mid)
    part1 = get_full_evolution_profile(pd, entry1, entry2, x1, x_mid)
    part2 = get_full_evolution_profile(pd, entry1, entry2, x_mid, x2)
    evolution_profile.update(part1)
    evolution_profile.update(part2)
    return evolution_profile
 def get_gppd_entries(self, open_el):
     if open_el in (self.entry1.composition +
                    self.entry2.composition).keys():
         gppd_entries = self.PDEntries
     else:
         comp = self.entry1.composition + self.entry2.composition + Composition(
             open_el.symbol)
         gppd_entries = VirtualEntry.from_composition(
             comp).get_GPPD_entries(open_el)
     return gppd_entries
Example #6
0
def get_phase_evolution_profile(args):
    """
    Provides the phase equilibria and decomposition energy evolution process of a phase when open to a specific element
    Chemical potential is referenced to pure phase of open element.
    """
    comp = Composition(args.composition)
    entry = VirtualEntry.from_composition(comp)
    oe = args.open_element
    entry.stabilize()
    print(entry.get_printable_evolution_profile(oe, allowpmu=args.posmu))
    return 0
    def __init__(self, entry1, entry2, entries=None, sup_el=None):
        comp1 = entry1.composition
        comp2 = entry2.composition
        norm1 = 1.0 / entry1.composition.num_atoms
        norm2 = 1.0 / entry2.composition.num_atoms

        self.entry1 = VirtualEntry.from_composition(entry1.composition * norm1,
                                                    energy=entry1.energy *
                                                    norm1,
                                                    name=comp1.reduced_formula)
        self.entry2 = VirtualEntry.from_composition(entry2.composition * norm2,
                                                    energy=entry2.energy *
                                                    norm2,
                                                    name=comp2.reduced_formula)

        if not entries:
            entry_mix = VirtualEntry.from_composition(comp1 + comp2)
            entries = entry_mix.get_PD_entries(sup_el=sup_el)
        entries += [entry1, entry2]
        self.PDEntries = entries
        self.PD = PhaseDiagram(entries)
    def get_gppd_transition_chempots(self, open_el, gppd_entries=None):
        """
        This is to get all possible transition chemical potentials from PD (rather than GPPD)
        Still use pure element ref.
        # May consider supporting negative miu in the future
        """
        if not gppd_entries:
            gppd_entries = self.get_gppd_entries(open_el)
        pd = PhaseDiagram(gppd_entries)
        vaspref_mius = pd.get_transition_chempots(Element(open_el))
        el_ref = VirtualEntry.get_mp_entry(open_el)

        elref_mius = [miu - el_ref.energy_per_atom for miu in vaspref_mius]
        return elref_mius
Example #9
0
def get_phase_equilibria_and_decomposition_energy_under_mu_from_composition(
        args):
    """
    Provide the phase equilibria and decomposition energy when open to one element with given miu
    Chemical potential is referenced to pure phase of open element.
    """
    comp = Composition(args.composition)
    chempot = {args.open_element: args.chemical_potential}
    entry = VirtualEntry.from_composition(comp)
    entry.stabilize()
    print(
        entry.get_printable_PE_and_decomposition_in_gppd(chempot,
                                                         entries=None))
    return 0
Example #10
0
def plot_vc(args):
    """
    Get the plot data of voltage profile.
    """
    comp = Composition(args.composition)
    entry = VirtualEntry.from_composition(comp)
    oe = args.open_element
    entry.stabilize()
    common_working_ions = dict(Li=1, Na=1, K=1, Mg=2, Ca=2, Al=3)
    valence = args.valence if args.valence else common_working_ions[oe]
    oe_list, v_list = entry.get_vc_plot_data(oe,
                                             valence=valence,
                                             allowpmu=args.posmu)
    print(entry.get_printable_vc_plot_data(oe, oe_list, v_list))
    entry.get_voltage_profile_plot(oe, oe_list, v_list, valence).show()
 def gppd_mixing(self, chempots, gppd_entries=None):
     """
     This function give the phase equilibria of a pseudo-binary in a open system (GPPD).
     It will give a complete evolution profile for mixing ratio x change from 0 to 1.
     x is the ratio (both entry norm. to 1 atom/fu(w/o open element) ) or each entry
     """
     open_el = list(chempots.keys())[0]
     el_ref = VirtualEntry.get_mp_entry(open_el)
     chempots[open_el] = chempots[open_el] + el_ref.energy_per_atom
     gppd_entry1 = GrandPotPDEntry(
         self.entry1, {Element[_]: chempots[_]
                       for _ in chempots})
     gppd_entry2 = GrandPotPDEntry(
         self.entry2, {Element[_]: chempots[_]
                       for _ in chempots})
     if not gppd_entries:
         gppd_entries = self.get_gppd_entries(open_el)
     gppd = GrandPotentialPhaseDiagram(gppd_entries, chempots)
     profile = get_full_evolution_profile(gppd, gppd_entry1, gppd_entry2, 0,
                                          1)
     cleaned = clean_profile(profile)
     return cleaned