File: test_electrodes.py

package info (click to toggle)
python-emmet-core 0.84.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 77,220 kB
  • sloc: python: 16,355; makefile: 30
file content (128 lines) | stat: -rw-r--r-- 4,638 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import pytest
from monty.serialization import loadfn
from pymatgen.apps.battery.conversion_battery import ConversionElectrode
from pymatgen.apps.battery.insertion_battery import InsertionElectrode
from pymatgen.core import Composition, Element
from pymatgen.analysis.phase_diagram import PhaseDiagram
from pymatgen.entries.computed_entries import ComputedEntry

from emmet.core.electrode import (
    ConversionElectrodeDoc,
    ConversionVoltagePairDoc,
    InsertionElectrodeDoc,
    InsertionVoltagePairDoc,
    get_battery_formula,
)


@pytest.fixture(scope="session")
def insertion_elec(test_dir):
    """
    Recycle the test cases from pymatgen
    """
    entry_Li = ComputedEntry("Li", -1.90753119)
    # more cases can be added later if problems are found
    entries_LTO = loadfn(test_dir / "LiTiO2_batt.json")
    ie_LTO = InsertionElectrode.from_entries(entries_LTO, entry_Li)

    d = {
        "LTO": (ie_LTO, entries_LTO[0].structure, entry_Li),
    }
    return d


@pytest.fixture(scope="session")
def conversion_elec(test_dir):
    conversion_electrodes = {}

    entries_LCO = loadfn(test_dir / "LiCoO2_batt.json")
    c = ConversionElectrode.from_composition_and_entries(
        Composition("LiCoO2"), entries_LCO, working_ion_symbol="Li"
    )
    conversion_electrodes["LiCoO2"] = {
        "working_ion": "Li",
        "CE": c,
        "entries": entries_LCO,
    }

    expected_properties = {
        "LiCoO2": {
            "average_voltage": 2.26940307125,
            "capacity_grav": 903.19752911225669,
            "capacity_vol": 2903.35804724,
            "energy_grav": 2049.7192465127678,
            "energy_vol": 6588.8896693479574,
        }
    }

    return {
        k: (conversion_electrodes[k], expected_properties[k])
        for k in conversion_electrodes.keys()
    }


def test_InsertionDocs(insertion_elec):
    for k, (elec, struct, wion_entry) in insertion_elec.items():
        # Make sure that main document can be created using an InsertionElectrode object
        ie = InsertionElectrodeDoc.from_entries(
            grouped_entries=elec.stable_entries,
            working_ion_entry=wion_entry,
            battery_id="mp-1234",
        )
        assert ie.average_voltage == elec.get_average_voltage()
        assert len(ie.material_ids) > 2
        # Make sure that each adjacent pair can be converted into a sub electrode
        for sub_elec in elec.get_sub_electrodes(adjacent_only=True):
            vp = InsertionVoltagePairDoc.from_sub_electrode(sub_electrode=sub_elec)
            assert vp.average_voltage == sub_elec.get_average_voltage()
            assert "mp" in vp.id_charge
        # assert type(ie.model_dump()["host_structure"]) == dict # This might be a requirement in the future


def test_ConversionDocs_from_entries(conversion_elec):
    for k, (elec, expected) in conversion_elec.items():
        vp = ConversionElectrodeDoc.from_composition_and_entries(
            Composition(k),
            entries=elec["entries"],
            working_ion_symbol=elec["working_ion"],
            battery_id="mp-1234",
            thermo_type="GGA_GGA+U",
        )
        res_d = vp.model_dump()
        for k, v in expected.items():
            assert res_d[k] == pytest.approx(v, 0.01)


def test_ConversionDocs_from_composition_and_pd(conversion_elec, test_dir):
    entries_LCO = loadfn(test_dir / "LiCoO2_batt.json")
    pd = PhaseDiagram(entries_LCO)
    for k, (elec, expected) in conversion_elec.items():
        vp = ConversionElectrodeDoc.from_composition_and_pd(
            comp=Composition(k),
            pd=pd,
            working_ion_symbol=elec["working_ion"],
            battery_id="mp-1234",
            thermo_type="GGA_GGA+U",
        )
        res_d = vp.model_dump()
        for k, v in expected.items():
            assert res_d[k] == pytest.approx(v, 0.01)


def test_ConversionDocs_from_sub_electrodes(conversion_elec):
    for k, (elec, expected) in conversion_elec.items():
        for sub_elec in elec["CE"].get_sub_electrodes(adjacent_only=True):
            vp = ConversionVoltagePairDoc.from_sub_electrode(sub_electrode=sub_elec)
            assert vp.average_voltage == sub_elec.get_average_voltage()


def test_get_battery_formula():
    test_cases = [
        (Composition("Li2CoO3"), Composition("Li7(CoO3)2"), Element("Li")),
        (Composition("Al4(CoO4)3"), Composition("Al2CoO4"), Element("Al")),
        (Composition("Li17(Co4O9)2"), Composition("Li21(Co4O9)2"), Element("Li")),
    ]

    results = [get_battery_formula(*case) for case in test_cases]

    assert results == ["Li2-3.5CoO3", "Al1.33-2CoO4", "Li8.5-10.5Co4O9"]