|
9 | 9 | from typing import TYPE_CHECKING
|
10 | 10 |
|
11 | 11 | from emmet.core.electronic_structure import BSPathType
|
12 |
| -from emmet.core.mpid import MPID |
| 12 | +from emmet.core.mpid import MPID, AlphaID |
13 | 13 | from emmet.core.settings import EmmetSettings
|
14 | 14 | from emmet.core.tasks import TaskDoc
|
15 | 15 | from emmet.core.thermo import ThermoType
|
@@ -1702,3 +1702,78 @@ def get_stability(
|
1702 | 1702 | }
|
1703 | 1703 | for idx, entry in enumerate(entries)
|
1704 | 1704 | ]
|
| 1705 | + |
| 1706 | + def get_oxygen_evolution( |
| 1707 | + self, |
| 1708 | + material_id: str | MPID | AlphaID, |
| 1709 | + working_ion: str | Element, |
| 1710 | + thermo_type: str | ThermoType = ThermoType.GGA_GGA_U, |
| 1711 | + ): |
| 1712 | + working_ion = Element(working_ion) |
| 1713 | + formatted_mpid = AlphaID(material_id).string |
| 1714 | + electrode_docs = self.materials.insertion_electrodes.search( |
| 1715 | + battery_ids=[f"{formatted_mpid}_{working_ion.value}"], |
| 1716 | + fields=["chemsys", "electrode_object", "framework"], |
| 1717 | + ) |
| 1718 | + if len(electrode_docs) == 0: |
| 1719 | + raise ValueError( |
| 1720 | + "No available insertion electrode data with MPID = " |
| 1721 | + f"{formatted_mpid} and working ion {working_ion.value}" |
| 1722 | + ) |
| 1723 | + if Element.O not in { |
| 1724 | + Element(ele) for ele in electrode_docs[0].chemsys.split("-") |
| 1725 | + }: |
| 1726 | + raise ValueError( |
| 1727 | + f"No oxygen in the host framework {electrode_docs[0].framework}" |
| 1728 | + ) |
| 1729 | + |
| 1730 | + inserted_chemsys = "-".join( |
| 1731 | + sorted({working_ion.value, *electrode_docs[0].chemsys.split("-")}) |
| 1732 | + ) |
| 1733 | + unique_composition = { |
| 1734 | + entry.composition |
| 1735 | + for entry in electrode_docs[0].electrode_object.get_all_entries() |
| 1736 | + } |
| 1737 | + |
| 1738 | + phase_diagram = self.materials.thermo.get_phase_diagram_from_chemsys( |
| 1739 | + inserted_chemsys, |
| 1740 | + thermo_type=ThermoType(thermo_type), |
| 1741 | + ) |
| 1742 | + |
| 1743 | + by_dict = { |
| 1744 | + composition.formula: [ |
| 1745 | + { |
| 1746 | + k: profile[v] |
| 1747 | + for k, v in { |
| 1748 | + "mu": "chempot", |
| 1749 | + "reaction": "reaction", |
| 1750 | + "evolution": "evolution", |
| 1751 | + }.items() |
| 1752 | + } |
| 1753 | + for profile in phase_diagram.get_element_profile("O", composition) |
| 1754 | + ] |
| 1755 | + for composition in unique_composition |
| 1756 | + } |
| 1757 | + |
| 1758 | + target_comp = Composition({"O": 1}) |
| 1759 | + for formula, data in by_dict.items(): |
| 1760 | + for idx, entry in enumerate(data): |
| 1761 | + # Normalize all reactions to have integer coefficients |
| 1762 | + scale = entry["reaction"].normalized_repr_and_factor()[1] |
| 1763 | + by_dict[formula][idx]["reaction"]._coeffs = [ |
| 1764 | + c * scale for c in entry["reaction"]._coeffs |
| 1765 | + ] |
| 1766 | + |
| 1767 | + by_dict[formula][idx]["O2_produced"] = ( |
| 1768 | + entry["reaction"].get_coeff(target_comp) |
| 1769 | + if target_comp in entry["reaction"].products |
| 1770 | + else 0 |
| 1771 | + ) |
| 1772 | + |
| 1773 | + return { |
| 1774 | + formula: { |
| 1775 | + k: [data[idx][k] for idx in range(len(data))] |
| 1776 | + for k in ("mu", "reaction", "evolution", "O2_produced") |
| 1777 | + } |
| 1778 | + for formula, data in by_dict.items() |
| 1779 | + } |
0 commit comments