Example #1
0
 def setUp(self):
     entrylist = list()
     weights = list()
     comp = Composition("Mn2O3")
     entry = PDEntry(comp, 49)
     entrylist.append(PourbaixEntry(entry))
     weights.append(1.0)
     comp = Ion.from_formula("MnO4[-]")
     entry = IonEntry(comp, 25)
     entrylist.append(PourbaixEntry(entry))
     weights.append(0.25)
     comp = Composition("Fe2O3")
     entry = PDEntry(comp, 50)
     entrylist.append(PourbaixEntry(entry))
     weights.append(0.5)
     comp = Ion.from_formula("Fe[2+]")
     entry = IonEntry(comp, 15)
     entrylist.append(PourbaixEntry(entry))
     weights.append(2.5)
     comp = Ion.from_formula("Fe[3+]")
     entry = IonEntry(comp, 20)
     entrylist.append(PourbaixEntry(entry))
     weights.append(1.5)
     self.weights = weights
     self.entrylist = entrylist
     self.multientry = MultiEntry(entrylist, weights)
def get_e_above_hull(formula, energy):
    atoms = Atoms(formula)
    full_symbols = atoms.get_chemical_symbols()
    symbols, counts = np.unique(full_symbols, return_counts=True)

    # list(set(atoms.get_chemical_symbols()))

    with MPRester() as m:
        data = m.get_entries_in_chemsys(symbols,
                                        compatible_only=True,
                                        property_data=[
                                            'energy_per_atom',
                                            'unit_cell_formula',
                                            'pretty_formula'
                                        ])
    PDentries = []

    for d in data:
        d = d.as_dict()
        PDentries += [PDEntry(d['data']['unit_cell_formula'], d['energy'])]
        print(d['data']['pretty_formula'], d['energy'])

    PD = PhaseDiagram(PDentries)

    # Need to apply MP corrections to +U calculations
    # MP advanced correction + anion correction

    #print(energy * 2, energy * 2 +  corr_energy * 2)

    PDE0 = PDEntry(formula, energy)
    e_hull = PD.get_e_above_hull(PDE0)

    return e_hull
Example #3
0
    def test_get_quasi_e_to_hull(self):
        for entry in self.pd.unstable_entries:
            # catch duplicated stable entries
            if entry.normalize(
                    inplace=False) in self.pd.get_stable_entries_normed():
                self.assertLessEqual(
                    self.pd.get_quasi_e_to_hull(entry), 0,
                    "Duplicated stable entries should have negative decomposition energy!"
                )
            else:
                self.assertGreaterEqual(
                    self.pd.get_quasi_e_to_hull(entry), 0,
                    "Unstable entries should have positive decomposition energy!"
                )

        for entry in self.pd.stable_entries:
            if entry.composition.is_element:
                self.assertEqual(
                    self.pd.get_quasi_e_to_hull(entry), 0,
                    "Stable elemental entries should have decomposition energy of zero!"
                )
            else:
                self.assertLessEqual(
                    self.pd.get_quasi_e_to_hull(entry), 0,
                    "Stable entries should have negative decomposition energy!"
                )

        novel_stable_entry = PDEntry("Li5FeO4", -999)
        self.assertLess(
            self.pd.get_quasi_e_to_hull(novel_stable_entry), 0,
            "Novel stable entries should have negative decomposition energy!")

        novel_unstable_entry = PDEntry("Li5FeO4", 999)
        self.assertGreater(
            self.pd.get_quasi_e_to_hull(novel_unstable_entry), 0,
            "Novel unstable entries should have positive decomposition energy!"
        )

        duplicate_entry = PDEntry("Li2O", -14.31361175)
        scaled_dup_entry = PDEntry("Li4O2", -14.31361175 * 2)
        stable_entry = [e for e in self.pd.stable_entries
                        if e.name == "Li2O"][0]

        self.assertEqual(
            self.pd.get_quasi_e_to_hull(duplicate_entry),
            self.pd.get_quasi_e_to_hull(stable_entry),
            "Novel duplicates of stable entries should have same decomposition energy!"
        )

        self.assertEqual(
            self.pd.get_quasi_e_to_hull(scaled_dup_entry),
            self.pd.get_quasi_e_to_hull(stable_entry),
            "Novel scaled duplicates of stable entries should have same decomposition energy!"
        )
Example #4
0
def _pd(structures, energies, ce):
    """
    Generate a phase diagram with the structures and energies
    """
    entries = []

    for s, e in zip(structures, energies):
        entries.append(PDEntry(s.composition.element_composition, e))

    max_e = max(entries, key=lambda e: e.energy_per_atom).energy_per_atom + 1000
    for el in ce.structure.composition.keys():
        entries.append(PDEntry(Composition({el: 1}).element_composition, max_e))

    return PhaseDiagram(entries)
Example #5
0
    def get_convex_hull_area(self, composition_space):
        """
        Prints out the area or volume of the convex hull defined by the
        organisms in the promotion set.
        """

        # make a phase diagram of just the organisms in the promotion set
        # (on the lower convex hull)
        pdentries = []
        for organism in self.promotion_set:
            pdentries.append(
                PDEntry(organism.composition, organism.total_energy))
        compound_pd = CompoundPhaseDiagram(pdentries,
                                           composition_space.endpoints)

        # get the data for the convex hull
        qhull_data = compound_pd.qhull_data
        # for some reason, the last point is positive, so remove it
        hull_data = np.delete(qhull_data, -1, 0)

        # make a ConvexHull object from the hull data
        try:
            convex_hull = ConvexHull(hull_data)
        except:
            return None
        if len(composition_space.endpoints) == 2:
            return convex_hull.area
        else:
            return convex_hull.volume
Example #6
0
class PDEntryTest(unittest.TestCase):
    def setUp(self):
        comp = Composition("LiFeO2")
        self.entry = PDEntry(comp, 53)
        self.gpentry = GrandPotPDEntry(self.entry, {Element("O"): 1.5})

    def test_get_energy(self):
        self.assertEqual(self.entry.energy, 53, "Wrong energy!")
        self.assertEqual(self.gpentry.energy, 50, "Wrong energy!")

    def test_get_chemical_energy(self):
        self.assertEqual(self.gpentry.chemical_energy, 3, "Wrong energy!")

    def test_get_energy_per_atom(self):
        self.assertEqual(self.entry.energy_per_atom, 53.0 / 4,
                         "Wrong energy per atom!")
        self.assertEqual(self.gpentry.energy_per_atom, 50.0 / 2,
                         "Wrong energy per atom!")

    def test_get_name(self):
        self.assertEqual(self.entry.name, "LiFeO2", "Wrong name!")
        self.assertEqual(self.gpentry.name, "LiFeO2", "Wrong name!")

    def test_get_composition(self):
        comp = self.entry.composition
        expected_comp = Composition("LiFeO2")
        self.assertEqual(comp, expected_comp, "Wrong composition!")
        comp = self.gpentry.composition
        expected_comp = Composition("LiFe")
        self.assertEqual(comp, expected_comp, "Wrong composition!")

    def test_is_element(self):
        self.assertFalse(self.entry.is_element)
        self.assertFalse(self.gpentry.is_element)

    def test_to_from_dict(self):
        d = self.entry.as_dict()
        gpd = self.gpentry.as_dict()
        entry = PDEntry.from_dict(d)

        self.assertEqual(entry.name, "LiFeO2", "Wrong name!")
        self.assertEqual(entry.energy_per_atom, 53.0 / 4)
        gpentry = GrandPotPDEntry.from_dict(gpd)
        self.assertEqual(gpentry.name, "LiFeO2", "Wrong name!")
        self.assertEqual(gpentry.energy_per_atom, 50.0 / 2)

        d_anon = d.copy()
        del d_anon["name"]
        try:
            entry = PDEntry.from_dict(d_anon)
        except KeyError:
            self.fail("Should not need to supply name!")

    def test_str(self):
        self.assertIsNotNone(str(self.entry))

    def test_read_csv(self):
        entries = EntrySet.from_csv(str(module_dir / "pdentries_test.csv"))
        self.assertEqual(entries.chemsys, {"Li", "Fe", "O"}, "Wrong elements!")
        self.assertEqual(len(entries), 490, "Wrong number of entries!")
Example #7
0
 def test_read_write_csv(self):
     Zn_solids = ["Zn", "ZnO", "ZnO2"]
     sol_g = [0.0, -3.338, -1.315]
     Zn_ions = ["Zn[2+]", "ZnOH[+]", "HZnO2[-]", "ZnO2[2-]", "ZnO"]
     liq_g = [-1.527, -3.415, -4.812, -4.036, -2.921]
     liq_conc = [1e-6, 1e-6, 1e-6, 1e-6, 1e-6]
     solid_entry = list()
     for sol in Zn_solids:
         comp = Composition(sol)
         delg = sol_g[Zn_solids.index(sol)]
         solid_entry.append(PourbaixEntry(PDEntry(comp, delg)))
     ion_entry = list()
     for ion in Zn_ions:
         comp_ion = Ion.from_formula(ion)
         delg = liq_g[Zn_ions.index(ion)]
         conc = liq_conc[Zn_ions.index(ion)]
         PoE = PourbaixEntry(IonEntry(comp_ion, delg))
         PoE.conc = conc
         ion_entry.append(PoE)
     entries = solid_entry + ion_entry
     PourbaixEntryIO.to_csv("pourbaix_test_entries.csv", entries)
     (elements,
      entries) = PourbaixEntryIO.from_csv("pourbaix_test_entries.csv")
     self.assertEqual(
         elements, [Element('Zn'),
                    Element('H'), Element('O')], "Wrong elements!")
     self.assertEqual(len(entries), 8, "Wrong number of entries!")
     os.remove("pourbaix_test_entries.csv")
Example #8
0
    def from_csv(cls, filename: str):
        """
        Imports PDEntries from a csv.

        Args:
            filename: Filename to import from.

        Returns:
            List of Elements, List of PDEntries
        """
        with open(filename, "r", encoding="utf-8") as f:
            reader = csv.reader(f,
                                delimiter=unicode2str(","),
                                quotechar=unicode2str("\""),
                                quoting=csv.QUOTE_MINIMAL)
            entries = list()
            header_read = False
            elements = None
            for row in reader:
                if not header_read:
                    elements = row[1:(len(row) - 1)]
                    header_read = True
                else:
                    name = row[0]
                    energy = float(row[-1])
                    comp = dict()
                    for ind in range(1, len(row) - 1):
                        if float(row[ind]) > 0:
                            comp[Element(elements[ind - 1])] = float(row[ind])
                    entries.append(PDEntry(Composition(comp), energy, name))
        return cls(entries)
Example #9
0
    def Create_Compositional_PhaseDiagram(self):

        phasediagram_entries = []

        for compound in self.compounds_info.keys():

            compound_composition = {}

            # Disregard elements not included in main compound
            if (compound in self.all_elements) and (compound
                                                    not in self.elements_list):
                continue

            # Elements
            if compound in self.elements_list:
                compound_composition[compound] = self.compounds_info[compound][
                    "dft_" + compound]

            # Compounds
            else:
                for element in self.compounds_info[compound]["elements_list"]:
                    compound_composition[element] = self.compounds_info[
                        compound]["dft_" + element]

            compound_total_energy = self.compounds_info[compound][
                "total_energy"]

            phasediagram_entries.append(
                PDEntry(compound_composition, compound_total_energy))

        self.phasediagram = PhaseDiagram(phasediagram_entries)
def get_decomp_product_ids(structures, competing_phases):
    # Create phase diagrams for each of the new structure chemical systems
    phase_diagrams = []
    for competing in competing_phases:
        # Add competing phases
        entries = [
            PDEntry(Composition(i['full_formula']),
                    i['final_energy'],
                    name=i['task_id']) for i in competing
        ]
        pd = PhaseDiagram(entries)
        phase_diagrams.append(pd)

    # Put new structures on phase diagram to get the set of decomp products
    all_decomp_prods = []
    for new_struc, pd in zip(structures, phase_diagrams):
        comp = new_struc['structure'].composition.element_composition
        decomp_prods = pd.get_decomposition(comp=comp)
        all_decomp_prods.extend([i.name for i in decomp_prods])

    # Reduce decomposition products to unique set
    all_decomp_prods = list(set(all_decomp_prods))
    print('{} unique competing phases to calculate'.format(
        len(all_decomp_prods)))
    return (all_decomp_prods)
Example #11
0
 def setUp(self):
     comp = Composition("Mn2O3")
     self.solentry = PDEntry(comp, 49)
     ion = Ion.from_formula("MnO4-")
     self.ionentry = IonEntry(ion, 25)
     self.PxIon = PourbaixEntry(self.ionentry)
     self.PxSol = PourbaixEntry(self.solentry)
     self.PxIon.conc = 1e-4
Example #12
0
 def setUp(self):
     comp = Composition("LiFeO2")
     entry = PDEntry(comp, 53)
     self.transformed_entry = TransformedPDEntry(
         {
             DummySpecies("Xa"): 1,
             DummySpecies("Xb"): 1
         }, entry)
Example #13
0
    def test_to_from_dict(self):
        d = self.entry.as_dict()
        gpd = self.gpentry.as_dict()
        entry = PDEntry.from_dict(d)

        self.assertEqual(entry.name, "LiFeO2", "Wrong name!")
        self.assertEqual(entry.energy_per_atom, 53.0 / 4)
        gpentry = GrandPotPDEntry.from_dict(gpd)
        self.assertEqual(gpentry.name, "LiFeO2", "Wrong name!")
        self.assertEqual(gpentry.energy_per_atom, 50.0 / 2)

        d_anon = d.copy()
        del d_anon["name"]
        try:
            entry = PDEntry.from_dict(d_anon)
        except KeyError:
            self.fail("Should not need to supply name!")
Example #14
0
    def from_entries(cls, entries, working_ion_entry):
        """
        Create a new InsertionElectrode.

        Args:
            entries: A list of ComputedStructureEntries (or subclasses)
                representing the different topotactic states of the battery,
                e.g. TiO2 and LiTiO2.
            working_ion_entry: A single ComputedEntry or PDEntry
                representing the element that carries charge across the
                battery, e.g. Li.
        """
        _working_ion = working_ion_entry.composition.elements[0]
        _working_ion_entry = working_ion_entry

        # Prepare to make phase diagram: determine elements and set their energy
        # to be very high
        elements = set()
        for entry in entries:
            elements.update(entry.composition.elements)

        # Set an artificial energy for each element for convex hull generation
        element_energy = max([entry.energy_per_atom for entry in entries]) + 10

        pdentries = []
        pdentries.extend(entries)
        pdentries.extend(
            [PDEntry(Composition({el: 1}), element_energy) for el in elements])

        # Make phase diagram to determine which entries are stable vs. unstable
        pd = PhaseDiagram(pdentries)

        def lifrac(e):
            return e.composition.get_atomic_fraction(_working_ion)

        # stable entries ordered by amount of Li asc
        _stable_entries = tuple(
            sorted([e for e in pd.stable_entries if e in entries], key=lifrac))

        # unstable entries ordered by amount of Li asc
        _unstable_entries = tuple(
            sorted([e for e in pd.unstable_entries if e in entries],
                   key=lifrac))

        # create voltage pairs
        _vpairs = tuple([
            InsertionVoltagePair.from_entries(
                _stable_entries[i],
                _stable_entries[i + 1],
                working_ion_entry,
            ) for i in range(len(_stable_entries) - 1)
        ])
        return cls(
            voltage_pairs=_vpairs,
            working_ion_entry=_working_ion_entry,
            _stable_entries=_stable_entries,
            _unstable_entries=_unstable_entries,
        )
Example #15
0
 def test_str(self):
     self.assertEqual(
         str(self.entry),
         "PDEntry : Li1 Fe1 O2 (mp-757614) with energy = 53.0000")
     pde = self.entry.as_dict()
     del pde["name"]
     pde = PDEntry.from_dict(pde)
     self.assertEqual(str(pde),
                      "PDEntry : Li1 Fe1 O2 with energy = 53.0000")
Example #16
0
    def is_in_composition_space_pd(self, organism, composition_space,
                                   constraints, pool):
        """
        Returns a boolean indicating whether the organism is in the composition
        space. Whether composition space endpoints are allowed is determined by
        the value of constraints.allow_endpoints.

        Args:
            organism: the Organism to check

            composition_space: the CompositionSpace of the search

            constraints: the Constraints of the search

            pool: the Pool
        """

        # cast the endpoints to PDEntries (just make up some energies)
        pdentries = []
        for endpoint in composition_space.endpoints:
            pdentries.append(PDEntry(endpoint, -10))
        pdentries.append(PDEntry(organism.composition, -10))

        # make a CompoundPhaseDiagram and use it to check if the organism
        # is in the composition space from how many entries it returns
        composition_checker = CompoundPhaseDiagram(pdentries,
                                                   composition_space.endpoints)
        if len(
                composition_checker.transform_entries(
                    pdentries, composition_space.endpoints)[0]) == len(
                        composition_space.endpoints):
            print('Organism {} lies outside the composition space '.format(
                organism.id))
            return False

        # check the composition space endpoints if specified
        if not constraints.allow_endpoints and len(pool.to_list()) > 0:
            for endpoint in composition_space.endpoints:
                if endpoint.almost_equals(
                        organism.composition.reduced_composition):
                    print('Organism {} is at a composition space '
                          'endpoint '.format(organism.id))
                    return False
        return True
Example #17
0
    def setUp(self):
        comp = Composition("LiFeO2")
        entry = PDEntry(comp, 53)

        terminal_compositions = ["Li2O", "FeO", "LiO8"]
        terminal_compositions = [Composition(c) for c in terminal_compositions]

        sp_mapping = OrderedDict()
        for i, comp in enumerate(terminal_compositions):
            sp_mapping[comp] = DummySpecies("X" + chr(102 + i))

        self.transformed_entry = TransformedPDEntry(entry, sp_mapping)
Example #18
0
 def from_dict(cls, d):
     """
     Invokes
     """
     entry_type = d["entry_type"]
     if entry_type == "Ion":
         entry = IonEntry.from_dict(d["entry"])
     else:
         entry = PDEntry.from_dict(d["entry"])
     entry_id = d["entry_id"]
     concentration = d["concentration"]
     return PourbaixEntry(entry, entry_id, concentration)
Example #19
0
 def from_dict(cls, d):
     """
     Invokes
     """
     entry_type = d["entry_type"]
     if entry_type == "Ion":
         entry = IonEntry.from_dict(d["entry"])
     else:
         entry = PDEntry.from_dict(d["entry"])
     entry_id = d["entry_id"]
     concentration = d["concentration"]
     return PourbaixEntry(entry, entry_id, concentration)
Example #20
0
 def from_dict(cls, d):
     """
     Returns a PourbaixEntry by reading in an Ion
     """
     entry_type = d["entry type"]
     if entry_type == "Ion":
         entry = IonEntry.from_dict(d["entry"])
     else:
         entry = PDEntry.from_dict(d["entry"])
     correction = d["correction"]
     entry_id = d["entry_id"]
     return PourbaixEntry(entry, correction, entry_id)
Example #21
0
 def from_dict(cls, d):
     """
     Returns a PourbaixEntry by reading in an Ion
     """
     entry_type = d["entry type"]
     if entry_type == "Ion":
         entry = IonEntry.from_dict(d["entry"])
     else:
         entry = PDEntry.from_dict(d["entry"])
     correction = d["correction"]
     entry_id = d["entry_id"]
     return PourbaixEntry(entry, correction, entry_id)
Example #22
0
    def setUp(self):
        entries = list(EntrySet.from_csv(os.path.join(module_dir, "pdentries_test.csv")))

        self.pd_ternary = PhaseDiagram(entries)
        self.plotter_ternary_mpl = PDPlotter(self.pd_ternary, backend="matplotlib")
        self.plotter_ternary_plotly = PDPlotter(self.pd_ternary, backend="plotly")

        entrieslio = [e for e in entries if "Fe" not in e.composition]
        self.pd_binary = PhaseDiagram(entrieslio)
        self.plotter_binary_mpl = PDPlotter(self.pd_binary, backend="matplotlib")
        self.plotter_binary_plotly = PDPlotter(self.pd_binary, backend="plotly")

        entries.append(PDEntry("C", 0))
        self.pd_quaternary = PhaseDiagram(entries)
        self.plotter_quaternary_mpl = PDPlotter(self.pd_quaternary, backend="matplotlib")
        self.plotter_quaternary_plotly = PDPlotter(self.pd_quaternary, backend="plotly")
Example #23
0
    def compute_pd_values(self, organisms_list, composition_space):
        """
        Constructs a convex hull from the provided organisms and sets the
        organisms' values to their distances from the convex hull.

        Returns the CompoundPhaseDiagram object computed from the organisms
        in organisms_list.

        Args:
            organisms_list: a list of Organisms whose values we need to compute

            composition_space: the CompositionSpace of the search
        """

        # create a PDEntry object for each organism in the list of organisms
        pdentries = {}
        for organism in organisms_list:
            pdentries[organism.id] = PDEntry(organism.composition,
                                             organism.total_energy)

        # put the pdentries in a list
        pdentries_list = []
        for organism_id in pdentries:
            pdentries_list.append(pdentries[organism_id])

        # create a compound phase diagram object from the list of pdentries
        compound_pd = CompoundPhaseDiagram(pdentries_list,
                                           composition_space.endpoints)

        # transform the pdentries and put them in a dictionary, with the
        # organism id's as the keys
        transformed_pdentries = {}
        for org_id in pdentries:
            transformed_pdentries[org_id] = compound_pd.transform_entries(
                [pdentries[org_id]], composition_space.endpoints)[0][0]

        # put the values in a dictionary, with the organism id's as the keys
        values = {}
        for org_id in pdentries:
            values[org_id] = compound_pd.get_e_above_hull(
                transformed_pdentries[org_id])

        # assign values to the organisms
        for organism in organisms_list:
            organism.value = values[organism.id]

        return compound_pd
Example #24
0
    def test_planar_inputs(self):
        e1 = PDEntry("H", 0)
        e2 = PDEntry("He", 0)
        e3 = PDEntry("Li", 0)
        e4 = PDEntry("Be", 0)
        e5 = PDEntry("B", 0)
        e6 = PDEntry("Rb", 0)

        pd = PhaseDiagram([e1, e2, e3, e4, e5, e6], map(Element, ["Rb", "He", "B", "Be", "Li", "H"]))

        self.assertEqual(len(pd.facets), 1)
Example #25
0
def getPourbaixEntryfromMongo(elements):
    entries = []
    unique_entries = {}
    elements_with_H_O = elements
    elements_with_H_O.append('H')
    elements_with_H_O.append('O')
    elements_with_H_O.sort()
    print(elements)
    allcombinations = getAllCombinations(elements_with_H_O)
    myclient = pymongo.MongoClient("mongodb://localhost:27017/")
    mydb = myclient["mp"]
    mycol = mydb["aml_all5"]
    for c in allcombinations:
        c.sort()
        p = '^'
        for i in c:
            p = p + i + '[0-9]+\s*'
        p = p + '$'
        mq = {"elements": c}
        md = mycol.find(mq)
        for x in md:
            print(x['pretty_formula'])
            fe = x['formation_energy_per_atom']
            if fe is not None:
                try:
                    fe = float(x['formation_energy_per_atom'])
                    if unique_entries.get(x['pretty_formula']) is not None:
                        if unique_entries[x['pretty_formula']] > x[
                                'formation_energy_per_atom'] * x['natoms']:
                            unique_entries[x['pretty_formula']] = x[
                                'formation_energy_per_atom'] * x['natoms']
                    else:
                        unique_entries[x['pretty_formula']] = x[
                            'formation_energy_per_atom'] * x['natoms']
                except ValueError:
                    fe = 100.0
                    print(x['task_id'], x['pretty_formula'], fe)
    for u in unique_entries:
        print(u, unique_entries[u])
        ent = PDEntry(Composition(u),
                      unique_entries[u],
                      attribute={'task_id': x['task_id']})
        ent = PourbaixEntry(ent)
        #ent.phase_type='Solid'
        entries.append(ent)
    return entries
    def Create_Compositional_PhaseDiagram(self):

        # Record all entries for the phase diagram
        phasediagram_entries = []

        for compound in self.compounds_info.keys():

            # Disregard elements not included in main compound
            if (compound in self.all_elements) and (compound
                                                    not in self.elements_list):
                continue

            # Get the compound's composition
            compound_composition = {}
            if compound in self.elements_list:  # Elemental material
                compound_composition[compound] = self.compounds_info[compound][
                    "dft_" + compound]
            else:  # Compound material
                for element in self.compounds_info[compound]["elements_list"]:
                    compound_composition[element] = self.compounds_info[
                        compound]["dft_" + element]

            # Get the compound's total energy
            compound_total_energy = self.compounds_info[compound][
                "total_energy"]

            # Record to list of entries
            phasediagram_entries.append(
                PDEntry(compound_composition, compound_total_energy))

        # Calculate compositional phase diagram (using pymatgen)
        #	The output data structure is as follows:
        #		lines --> List of arrays, each array is 2x2 for ternary (3x3 for quaternary, etc.), column vector represents point on phase diagram.
        #					ex: array([ [0.3, 0.5], [1.0, 0.0] ]) is a line that goes from point [x=0.3, y=1.0] to point [x=0.5, y=0.0]
        #		labels --> Dictionary with point-PDEntry pairs.
        self.pmg_phasediagram = PhaseDiagram(phasediagram_entries)
        self.pmg_phasediagram_plot_object = PDPlotter(self.pmg_phasediagram)
        (lines, labels,
         unstable) = self.pmg_phasediagram_plot_object.pd_plot_data

        # Record all lines and points of the compositional phase diagram
        self.lines = lines
        self.labels = labels
Example #27
0
    def get_phase_diagram_plot(self):
        """
        Returns a phase diagram plot, as a matplotlib plot object.
        """

        # set the font to Times, rendered with Latex
        plt.rc('font', **{'family': 'serif', 'serif': ['Times']})
        plt.rc('text', usetex=True)

        # parse the composition space endpoints
        endpoints_line = self.lines[0].split()
        endpoints = []
        for word in endpoints_line[::-1]:
            if word == 'endpoints:':
                break
            else:
                endpoints.append(Composition(word))

        if len(endpoints) < 2:
            print('There must be at least 2 endpoint compositions to make a '
                  'phase diagram.')
            quit()

        # parse the compositions and total energies of all the structures
        compositions = []
        total_energies = []
        for i in range(4, len(self.lines)):
            line = self.lines[i].split()
            compositions.append(Composition(line[1]))
            total_energies.append(float(line[2]))

        # make a list of PDEntries
        pdentries = []
        for i in range(len(compositions)):
            pdentries.append(PDEntry(compositions[i], total_energies[i]))

        # make a CompoundPhaseDiagram
        compound_pd = CompoundPhaseDiagram(pdentries, endpoints)

        # make a PhaseDiagramPlotter
        pd_plotter = PDPlotter(compound_pd, show_unstable=50)
        return pd_plotter.get_plot(label_unstable=False)
Example #28
0
    def from_csv(filename):
        """
        Imports PourbaixEntries from a csv.

        Args:
            filename: Filename to import from.

        Returns:
            List of Entries
        """
        with open(filename, "rt") as f:
            reader = csv.reader(f,
                                delimiter=unicode2str(","),
                                quotechar=unicode2str("\""),
                                quoting=csv.QUOTE_MINIMAL)
            entries = list()
            header_read = False
            for row in reader:
                if not header_read:
                    elements = row[1:(len(row) - 4)]
                    header_read = True
                elif row:
                    name = row[0]
                    energy = float(row[-4])
                    conc = float(row[-1])
                    comp = dict()
                    for ind in range(1, len(row) - 4):
                        if float(row[ind]) > 0:
                            comp[Element(elements[ind - 1])] = float(row[ind])
                    phase_type = row[-3]
                    if phase_type == "Ion":
                        PoE = PourbaixEntry(
                            IonEntry(Ion.from_formula(name), energy))
                        PoE.conc = conc
                        PoE.name = name
                        entries.append(PoE)
                    else:
                        entries.append(
                            PourbaixEntry(PDEntry(Composition(comp), energy)))
        elements = [Element(el) for el in elements]
        return elements, entries
Example #29
0
    def get_convex_hull_area(self, composition_space):
        """
        Returns the area/volume of the current convex hull.

        Args:
            composition_space: the CompositionSpace of the search
        """

        # check if the initial population contains organisms at all the
        # endpoints of the composition space
        if self.has_endpoints(composition_space) and \
                self.has_non_endpoint(composition_space):

            # compute and print the area or volume of the convex hull
            pdentries = []
            for organism in self.initial_population:
                pdentries.append(
                    PDEntry(organism.composition, organism.total_energy))
            compound_pd = CompoundPhaseDiagram(pdentries,
                                               composition_space.endpoints)

            # get the data for the convex hull
            qhull_data = compound_pd.qhull_data
            # for some reason, the last point is positive, so remove it
            hull_data = np.delete(qhull_data, -1, 0)

            # make a ConvexHull object from the hull data
            # Sometime this fails, saying that only two points were given to
            # construct the convex hull, even though the if statement above
            # checks that there are enough points.
            try:
                convex_hull = ConvexHull(hull_data)
            except:
                return None
            if len(composition_space.endpoints) == 2:
                return convex_hull.area
            else:
                return convex_hull.volume
        def update_entries_store(rows):
            if rows is None:
                raise PreventUpdate
            entries = []
            for row in rows:
                try:
                    comp = Composition(row["Formula"])
                    energy = row["Formation Energy (eV/atom)"]
                    if row["Material ID"] is None:
                        attribute = "Custom Entry"
                    else:
                        attribute = row["Material ID"]
                    entry = PDEntry(comp,
                                    float(energy) * comp.num_atoms,
                                    attribute=attribute)
                    entries.append(entry)
                except:
                    pass

            if not entries:
                raise PreventUpdate

            return self.to_data(entries)
Example #31
0
        def update_entries_store(rows):
            if rows is None:
                raise PreventUpdate
            entries = []
            for row in rows:
                try:
                    comp = Composition(row["Formula"])
                    energy = row["Formation Energy (eV/atom)"]
                    if row["Material ID"] is None:
                        attribute = "Custom Entry"
                    else:
                        attribute = row["Material ID"]
                    # create new entry object containing mpid as attribute (to combine with custom entries)
                    entry = PDEntry(comp,
                                    float(energy) * comp.num_atoms,
                                    attribute=attribute)
                    entries.append(entry)
                except:
                    continue

            if not entries:
                raise PreventUpdate

            return entries
Example #32
0
 def test_1d_pd(self):
     entry = PDEntry("H", 0)
     pd = PhaseDiagram([entry])
     decomp, e = pd.get_decomp_and_e_above_hull(PDEntry("H", 1))
     self.assertAlmostEqual(e, 1)
     self.assertAlmostEqual(decomp[entry], 1.0)