Example #1
0
    def setUp(self):
        self.temps = [300, 600, 900, 1200, 1500, 1800]
        self.struct = vasprun.final_structure
        self.num_atoms = self.struct.composition.num_atoms
        self.entries_with_temps = {
            temp: GibbsComputedStructureEntry(
                self.struct,
                -2.436,
                temp=temp,
                gibbs_model="SISSO",
                parameters=vasprun.incar,
                entry_id="test",
            )
            for temp in self.temps
        }

        with open(
                os.path.join(PymatgenTest.TEST_FILES_DIR, "Mn-O_entries.json"),
                "r") as f:
            data = json.load(f)
        with open(
                os.path.join(PymatgenTest.TEST_FILES_DIR,
                             "structure_CO2.json"), "r") as f:
            self.co2_struct = MontyDecoder().process_decoded(json.load(f))

        self.mp_entries = [MontyDecoder().process_decoded(d) for d in data]
Example #2
0
 def get_gibbs_computed_structure_entries(self, entries):
     entries_comp = [entry.composition for entry in entries]
     ele_entries = self.get_element_entries(entries)
     gibbs_computed_structure_entries = GibbsComputedStructureEntry.from_entries(
         list(set(entries + ele_entries)), temp=self.temp)
     return [
         entry for entry in gibbs_computed_structure_entries
         if entry.composition in entries_comp
     ]
    def setUp(self):
        self.temps = [300, 600, 900, 1200, 1500, 1800]
        self.struct = vasprun.final_structure
        self.num_atoms = self.struct.composition.num_atoms
        self.temp_entries = {
            temp: GibbsComputedStructureEntry(
                self.struct,
                -2.436 * self.num_atoms,
                temp=temp,
                parameters=vasprun.incar,
                entry_id="test",
            )
            for temp in self.temps
        }

        with open(os.path.join(test_dir, "Mn-O_entries.json"), "r") as f:
            data = json.load(f)

        self.mp_entries = [MontyDecoder().process_decoded(d) for d in data]
Example #4
0
    def _filter_entries(all_entries,
                        e_above_hull,
                        temp,
                        include_polymorphs=False):
        """
        Helper method for filtering entries by specified energy above hull

        Args:
            all_entries ([ComputedEntry]): List of ComputedEntry-like objects to be
                filtered
            e_above_hull (float): Thermodynamic stability threshold (energy above hull)
                [eV/atom]
            include_polymorphs (bool): whether to include higher energy polymorphs of
                existing structures

        Returns:
            [ComputedEntry]: list of all entries with energies above hull equal to or
                less than the specified e_above_hull.
        """
        pd_dict = expand_pd(all_entries)
        pd_dict = {
            chemsys:
            PhaseDiagram(GibbsComputedStructureEntry.from_pd(pd, temp))
            for chemsys, pd in pd_dict.items()
        }

        filtered_entries = set()
        all_comps = dict()
        for chemsys, pd in pd_dict.items():
            for entry in pd.all_entries:
                if (entry in filtered_entries
                        or pd.get_e_above_hull(entry) > e_above_hull):
                    continue
                formula = entry.composition.reduced_formula
                if not include_polymorphs and (formula in all_comps):
                    if all_comps[
                            formula].energy_per_atom < entry.energy_per_atom:
                        continue
                    filtered_entries.remove(all_comps[formula])
                all_comps[formula] = entry
                filtered_entries.add(entry)

        return pd_dict, list(filtered_entries)
Example #5
0
    def get_entries_in_chemsys(
        self,
        elements: Union[str, List[str]],
        use_gibbs: Optional[int] = None,
    ):
        """
        Helper method to get a list of ComputedEntries in a chemical system.
        For example, elements = ["Li", "Fe", "O"] will return a list of all
        entries in the Li-Fe-O chemical system, i.e., all LixOy,
        FexOy, LixFey, LixFeyOz, Li, Fe and O phases. Extremely useful for
        creating phase diagrams of entire chemical systems.
        Args:
            elements (str or [str]): Chemical system string comprising element
                symbols separated by dashes, e.g., "Li-Fe-O" or List of element
                symbols, e.g., ["Li", "Fe", "O"].
            use_gibbs: If None (default), DFT energy is returned. If a number, return
                the free energy of formation estimated using a machine learning model
                (see GibbsComputedStructureEntry). The number is the temperature in
                Kelvin at which to estimate the free energy. Must be between 300 K and
                2000 K.
        Returns:
            List of ComputedEntries.
        """
        if isinstance(elements, str):
            elements = elements.split("-")

        all_chemsyses = []
        for i in range(len(elements)):
            for els in itertools.combinations(elements, i + 1):
                all_chemsyses.append("-".join(sorted(els)))

        entries = []  # type: List[ComputedEntry]

        entries.extend(self.get_entries(all_chemsyses))

        if use_gibbs:
            # replace the entries with GibbsComputedStructureEntry
            from pymatgen.entries.computed_entries import GibbsComputedStructureEntry

            entries = GibbsComputedStructureEntry.from_entries(entries,
                                                               temp=use_gibbs)

        return entries
    def setUp(self):
        with pytest.warns(FutureWarning, match="MaterialsProjectCompatibility will be updated"):
            self.temps = [300, 600, 900, 1200, 1500, 1800]
            self.struct = vasprun.final_structure
            self.num_atoms = self.struct.composition.num_atoms
            self.temp_entries = {
                temp: GibbsComputedStructureEntry(
                    self.struct,
                    -2.436 * self.num_atoms,
                    temp=temp,
                    parameters=vasprun.incar,
                    entry_id="test",
                )
                for temp in self.temps
            }

            with open(os.path.join(PymatgenTest.TEST_FILES_DIR, "Mn-O_entries.json"), "r") as f:
                data = json.load(f)

            self.mp_entries = [MontyDecoder().process_decoded(d) for d in data]
Example #7
0
 def test_to_from_dict(self):
     test_entry = self.temp_entries[300]
     d = test_entry.as_dict()
     e = GibbsComputedStructureEntry.from_dict(d)
     self.assertAlmostEqual(e.energy, test_entry.energy)
Example #8
0
 def test_from_pd(self):
     pd = PhaseDiagram(self.mp_entries)
     gibbs_entries = GibbsComputedStructureEntry.from_pd(pd)
     self.assertIsNotNone(gibbs_entries)
Example #9
0
 def test_from_entries(self):
     gibbs_entries = GibbsComputedStructureEntry.from_entries(
         self.mp_entries)
     self.assertIsNotNone(gibbs_entries)
Example #10
0
 def test_interpolation(self):
     temp = 450
     e = GibbsComputedStructureEntry(self.struct,
                                     -2.436 * self.num_atoms,
                                     temp=temp)
     self.assertAlmostEqual(e.energy, -53.7243542548528)
Example #11
0
 def test_expt_gas_entry(self):
     co2_entry = GibbsComputedStructureEntry(self.co2_struct, 0, temp=900)
     self.assertAlmostEqual(co2_entry.energy, -16.406560223724014)
     self.assertAlmostEqual(co2_entry.energy_per_atom, -1.3672133519770011)
Example #12
0
    def get_pourbaix_entries(
        self,
        chemsys: Union[str, List],
        solid_compat="MaterialsProject2020Compatibility",
        use_gibbs: Optional[Literal[300]] = None,
    ):
        """
        A helper function to get all entries necessary to generate
        a Pourbaix diagram from the rest interface.

        Args:
            chemsys (str or [str]): Chemical system string comprising element
                symbols separated by dashes, e.g., "Li-Fe-O" or List of element
                symbols, e.g., ["Li", "Fe", "O"].
            solid_compat: Compatiblity scheme used to pre-process solid DFT energies prior
                to applying aqueous energy adjustments. May be passed as a class (e.g.
                MaterialsProject2020Compatibility) or an instance
                (e.g., MaterialsProject2020Compatibility()). If None, solid DFT energies
                are used as-is. Default: MaterialsProject2020Compatibility
            use_gibbs: Set to 300 (for 300 Kelvin) to use a machine learning model to
                estimate solid free energy from DFT energy (see GibbsComputedStructureEntry).
                This can slightly improve the accuracy of the Pourbaix diagram in some
                cases. Default: None. Note that temperatures other than 300K are not
                permitted here, because MaterialsProjectAqueousCompatibility corrections,
                used in Pourbaix diagram construction, are calculated based on 300 K data.
        """
        # imports are not top-level due to expense
        from pymatgen.analysis.pourbaix_diagram import PourbaixEntry
        from pymatgen.entries.compatibility import (
            Compatibility,
            MaterialsProject2020Compatibility,
            MaterialsProjectAqueousCompatibility,
            MaterialsProjectCompatibility,
        )
        from pymatgen.entries.computed_entries import ComputedEntry

        if solid_compat == "MaterialsProjectCompatibility":
            solid_compat = MaterialsProjectCompatibility()
        elif solid_compat == "MaterialsProject2020Compatibility":
            solid_compat = MaterialsProject2020Compatibility()
        elif isinstance(solid_compat, Compatibility):
            solid_compat = solid_compat
        else:
            raise ValueError(
                "Solid compatibility can only be 'MaterialsProjectCompatibility', "
                "'MaterialsProject2020Compatibility', or an instance of a Compatability class"
            )

        pbx_entries = []

        if isinstance(chemsys, str):
            chemsys = chemsys.split("-")
        # capitalize and sort the elements
        chemsys = sorted(e.capitalize() for e in chemsys)

        # Get ion entries first, because certain ions have reference
        # solids that aren't necessarily in the chemsys (Na2SO4)

        # download the ion reference data from MPContribs
        ion_data = self.get_ion_reference_data_for_chemsys(chemsys)

        # build the PhaseDiagram for get_ion_entries
        ion_ref_comps = [
            Ion.from_formula(d["data"]["RefSolid"]).composition
            for d in ion_data
        ]
        ion_ref_elts = set(
            itertools.chain.from_iterable(i.elements for i in ion_ref_comps))
        # TODO - would be great if the commented line below would work
        # However for some reason you cannot process GibbsComputedStructureEntry with
        # MaterialsProjectAqueousCompatibility
        ion_ref_entries = self.get_entries_in_chemsys(
            list([str(e) for e in ion_ref_elts] + ["O", "H"]),
            # use_gibbs=use_gibbs
        )

        # suppress the warning about supplying the required energies; they will be calculated from the
        # entries we get from MPRester
        with warnings.catch_warnings():
            warnings.filterwarnings(
                "ignore",
                message="You did not provide the required O2 and H2O energies.",
            )
            compat = MaterialsProjectAqueousCompatibility(
                solid_compat=solid_compat)
        # suppress the warning about missing oxidation states
        with warnings.catch_warnings():
            warnings.filterwarnings(
                "ignore", message="Failed to guess oxidation states.*")
            ion_ref_entries = compat.process_entries(ion_ref_entries)
        # TODO - if the commented line above would work, this conditional block
        # could be removed
        if use_gibbs:
            # replace the entries with GibbsComputedStructureEntry
            from pymatgen.entries.computed_entries import GibbsComputedStructureEntry

            ion_ref_entries = GibbsComputedStructureEntry.from_entries(
                ion_ref_entries, temp=use_gibbs)
        ion_ref_pd = PhaseDiagram(ion_ref_entries)

        ion_entries = self.get_ion_entries(ion_ref_pd, ion_ref_data=ion_data)
        pbx_entries = [
            PourbaixEntry(e, f"ion-{n}") for n, e in enumerate(ion_entries)
        ]

        # Construct the solid pourbaix entries from filtered ion_ref entries
        extra_elts = (set(ion_ref_elts) - {Element(s)
                                           for s in chemsys} -
                      {Element("H"), Element("O")})
        for entry in ion_ref_entries:
            entry_elts = set(entry.composition.elements)
            # Ensure no OH chemsys or extraneous elements from ion references
            if not (entry_elts <= {Element("H"), Element("O")}
                    or extra_elts.intersection(entry_elts)):
                # Create new computed entry
                form_e = ion_ref_pd.get_form_energy(entry)
                new_entry = ComputedEntry(entry.composition,
                                          form_e,
                                          entry_id=entry.entry_id)
                pbx_entry = PourbaixEntry(new_entry)
                pbx_entries.append(pbx_entry)

        return pbx_entries