def setUp(self): self.entry_Li = ComputedEntry("Li", -1.90753119) with open(os.path.join(test_dir, "LiTiO2_batt.json"), "r") as f: self.entries_LTO = json.load(f, cls=PMGJSONDecoder) self.ie_LTO = InsertionElectrode(self.entries_LTO, self.entry_Li)
def setUp(self): self.entry_Li = ComputedEntry("Li", -1.90753119) with open(os.path.join(test_dir, "LiTiO2_batt.json"), "r") as f: self.entries_LTO = json.load(f, cls=MontyDecoder) with open(os.path.join(test_dir, "MgVO_batt.json"), "r") as file: self.entries_MVO = json.load(file, cls=MontyDecoder) with open(os.path.join(test_dir, "Mg_batt.json"), "r") as file: self.entry_Mg = json.load(file, cls=MontyDecoder) self.ie_LTO = InsertionElectrode(self.entries_LTO, self.entry_Li) self.ie_MVO = InsertionElectrode(self.entries_MVO, self.entry_Mg)
def from_entries( cls, grouped_entries: List[ComputedEntry], working_ion_entry: ComputedEntry, battery_id: str, host_structure: Structure, ) -> Union["InsertionElectrodeDoc", None]: try: ie = InsertionElectrode.from_entries( entries=grouped_entries, working_ion_entry=working_ion_entry, strip_structures=True, ) except IndexError: return None d = ie.get_summary_dict() d["material_ids"] = d["stable_material_ids"] + d[ "unstable_material_ids"] d["num_steps"] = d.pop("nsteps", None) d["last_updated"] = datetime.utcnow() elements = sorted(host_structure.composition.elements) chemsys = "-".join(sorted(map(str, elements))) framework = Composition(d["framework_formula"]) return cls(battery_id=battery_id, host_structure=host_structure.as_dict(), framework=framework, electrode_object=ie.as_dict(), elements=elements, nelements=len(elements), chemsys=chemsys, formula_anonymous=framework.anonymized_formula, **d)
def build_battery(e_l, wi): """build_battery Builds an InsertionElectrode from ComputedStructureEntries. :param s_l: List of entries for various states of charge. :param wi: Charge-carrier ion for the battery. (String) :return: An InsertionElectrode object. """ with MPRester(mp_api) as m: wi_entry = m.get_entry_by_material_id(wi_ids[wi], inc_structure=True) return InsertionElectrode(e_l, wi_entry)
def setUp(self): entry_Li = ComputedEntry("Li", -1.90753119) with open(os.path.join(test_dir, "LiTiO2_batt.json"), "r") as f: entries_LTO = json.load(f, cls=MontyDecoder) self.ie_LTO = InsertionElectrode.from_entries( entries_LTO, entry_Li) with open(os.path.join(test_dir, "FeF3_batt.json"), "r") as fid: entries = json.load(fid, cls=MontyDecoder) self.ce_FF = ConversionElectrode.from_composition_and_entries( Composition("FeF3"), entries)
def test_to_from_dict(self): d = self.ie_LTO.as_dict() ie = InsertionElectrode.from_dict(d) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3) #Just to make sure json string works. json_str = json.dumps(self.ie_LTO, cls=MontyEncoder) ie = json.loads(json_str, cls=MontyDecoder) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3)
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
class InsertionElectrodeTest(unittest.TestCase): def setUp(self): self.entry_Li = ComputedEntry("Li", -1.90753119) self.entry_Ca = ComputedEntry("Ca", -1.99689568) with open(os.path.join(test_dir, "LiTiO2_batt.json"), "r") as f: self.entries_LTO = json.load(f, cls=MontyDecoder) with open(os.path.join(test_dir, "MgVO_batt.json"), "r") as file: self.entries_MVO = json.load(file, cls=MontyDecoder) with open(os.path.join(test_dir, "Mg_batt.json"), "r") as file: self.entry_Mg = json.load(file, cls=MontyDecoder) with open(os.path.join(test_dir, "CaMoO2_batt.json"), "r") as f: self.entries_CMO = json.load(f, cls=MontyDecoder) self.ie_LTO = InsertionElectrode(self.entries_LTO, self.entry_Li) self.ie_MVO = InsertionElectrode(self.entries_MVO, self.entry_Mg) self.ie_CMO = InsertionElectrode(self.entries_CMO, self.entry_Ca) def test_voltage(self): #test basic voltage self.assertAlmostEqual(self.ie_LTO.max_voltage, 2.78583901, 3) self.assertAlmostEqual(self.ie_LTO.min_voltage, 0.89702381, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(), 1.84143141, 3) #test voltage range selectors self.assertAlmostEqual(self.ie_LTO.get_average_voltage(0, 1), 0.89702381, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(2, 3), 2.78583901, 3) #test non-existing voltage range self.assertAlmostEqual(self.ie_LTO.get_average_voltage(0, 0.1), 0, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(4, 5), 0, 3) self.assertAlmostEqual(self.ie_MVO.get_average_voltage(), 2.513767, 3) def test_capacities(self): #test basic capacity self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(), 308.74865045, 3) self.assertAlmostEqual(self.ie_LTO.get_capacity_vol(), 1205.99391136, 3) #test capacity selector self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(1, 3), 154.374325225, 3) #test alternate normalization option self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(1, 3, False), 160.803169506, 3) self.assertIsNotNone(self.ie_LTO.as_dict_summary(True)) self.assertAlmostEqual(self.ie_MVO.get_capacity_grav(), 281.845548242, 3) self.assertAlmostEqual(self.ie_MVO.get_capacity_vol(), 1145.80087994, 3) def test_get_instability(self): self.assertIsNone(self.ie_LTO.get_max_instability()) self.assertAlmostEqual(self.ie_MVO.get_max_instability(), 0.7233711650000014) self.assertAlmostEqual(self.ie_MVO.get_min_instability(), 0.4913575099999994) def test_get_muO2(self): self.assertIsNone(self.ie_LTO.get_max_muO2()) self.assertAlmostEqual(self.ie_MVO.get_max_muO2(), -4.93552791875) self.assertAlmostEqual(self.ie_MVO.get_min_muO2(), -11.06599657) def test_entries(self): #test that the proper number of sub-electrodes are returned self.assertEqual(len(self.ie_LTO.get_sub_electrodes(False, True)), 3) self.assertEqual(len(self.ie_LTO.get_sub_electrodes(True, True)), 2) def test_get_all_entries(self): self.ie_LTO.get_all_entries() def test_to_from_dict(self): d = self.ie_LTO.as_dict() ie = InsertionElectrode.from_dict(d) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3) #Just to make sure json string works. json_str = json.dumps(self.ie_LTO, cls=MontyEncoder) ie = json.loads(json_str, cls=MontyDecoder) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3) def test_voltage_pair(self): vpair = self.ie_LTO[0] self.assertAlmostEqual(vpair.voltage, 2.78583901) self.assertAlmostEqual(vpair.mAh, 13400.7411749, 2) self.assertAlmostEqual(vpair.mass_charge, 79.8658) self.assertAlmostEqual(vpair.mass_discharge, 83.3363) self.assertAlmostEqual(vpair.vol_charge, 37.553684467) self.assertAlmostEqual(vpair.vol_discharge, 37.917719932) self.assertAlmostEqual(vpair.frac_charge, 0.0) self.assertAlmostEqual(vpair.frac_discharge, 0.14285714285714285) def test_as_dict_summary(self): d = self.ie_CMO.as_dict_summary() self.assertAlmostEqual(d['stability_charge'], 0.2346574583333325) self.assertAlmostEqual(d['stability_discharge'], 0.33379544031249786) self.assertAlmostEqual(d['muO2_data']['mp-714969'][0]['chempot'], -4.93552791875)
class InsertionElectrodeTest(unittest.TestCase): def setUp(self): self.entry_Li = ComputedEntry("Li", -1.90753119) with open(os.path.join(test_dir, "LiTiO2_batt.json"), "r") as f: self.entries_LTO = json.load(f, cls=MontyDecoder) with open(os.path.join(test_dir, "MgVO_batt.json"), "r") as file: self.entries_MVO = json.load(file, cls=MontyDecoder) with open(os.path.join(test_dir, "Mg_batt.json"), "r") as file: self.entry_Mg = json.load(file, cls=MontyDecoder) self.ie_LTO = InsertionElectrode(self.entries_LTO, self.entry_Li) self.ie_MVO = InsertionElectrode(self.entries_MVO, self.entry_Mg) def test_voltage(self): #test basic voltage self.assertAlmostEqual(self.ie_LTO.max_voltage, 2.78583901, 3) self.assertAlmostEqual(self.ie_LTO.min_voltage, 0.89702381, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(), 1.84143141, 3) #test voltage range selectors self.assertAlmostEqual(self.ie_LTO.get_average_voltage(0, 1), 0.89702381, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(2, 3), 2.78583901, 3) #test non-existing voltage range self.assertAlmostEqual(self.ie_LTO.get_average_voltage(0, 0.1), 0, 3) self.assertAlmostEqual(self.ie_LTO.get_average_voltage(4, 5), 0, 3) self.assertAlmostEqual(self.ie_MVO.get_average_voltage(), 2.513767,3) def test_capacities(self): #test basic capacity self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(), 308.74865045, 3) self.assertAlmostEqual(self.ie_LTO.get_capacity_vol(), 1205.99391136, 3) #test capacity selector self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(1, 3), 154.374325225, 3) #test alternate normalization option self.assertAlmostEqual(self.ie_LTO.get_capacity_grav(1, 3, False), 160.803169506, 3) self.assertIsNotNone(self.ie_LTO.as_dict_summary(True)) self.assertAlmostEqual(self.ie_MVO.get_capacity_grav(), 281.845548242, 3) self.assertAlmostEqual(self.ie_MVO.get_capacity_vol(), 1145.80087994, 3) def test_get_muO2(self): self.assertIsNone(self.ie_LTO.get_max_muO2()) def test_entries(self): #test that the proper number of sub-electrodes are returned self.assertEqual(len(self.ie_LTO.get_sub_electrodes(False, True)), 3) self.assertEqual(len(self.ie_LTO.get_sub_electrodes(True, True)), 2) def test_get_all_entries(self): self.ie_LTO.get_all_entries() def test_to_from_dict(self): d = self.ie_LTO.as_dict() ie = InsertionElectrode.from_dict(d) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3) #Just to make sure json string works. json_str = json.dumps(self.ie_LTO, cls=MontyEncoder) ie = json.loads(json_str, cls=MontyDecoder) self.assertAlmostEqual(ie.max_voltage, 2.78583901, 3) self.assertAlmostEqual(ie.min_voltage, 0.89702381, 3) self.assertAlmostEqual(ie.get_average_voltage(), 1.84143141, 3) def test_voltage_pair(self): vpair = self.ie_LTO[0] self.assertAlmostEqual(vpair.voltage, 2.78583901) self.assertAlmostEqual(vpair.mAh, 13400.7411749, 2) self.assertAlmostEqual(vpair.mass_charge, 79.8658) self.assertAlmostEqual(vpair.mass_discharge, 83.3363) self.assertAlmostEqual(vpair.vol_charge, 37.553684467) self.assertAlmostEqual(vpair.vol_discharge, 37.917719932) self.assertAlmostEqual(vpair.frac_charge, 0.0) self.assertAlmostEqual(vpair.frac_discharge, 0.14285714285714285)
def process_item(self, item): """ Read the entries from the thermo database and group them based on the reduced composition of the framework material (without working ion). Args: chemsys(string): the chemical system string to be queried returns: (chemsys, [group]): entry contains a list of entries the materials together by composition """ # sort the entries intro subgroups # then perform PD analysis all_entries = item["all_entries"] pd_ents = item["pd_ents"] phdi = PhaseDiagram(pd_ents) # The working ion entries ents_wion = list( filter( lambda x: x.composition.get_integer_formula_and_factor()[0] == self.working_ion, pd_ents, ) ) self.working_ion_entry = min(ents_wion, key=lambda e: e.energy_per_atom) assert self.working_ion_entry != None grouped_entries = list(self.get_sorted_subgroups(all_entries)) docs = [] # results for group in grouped_entries: self.logger.debug( f"Grouped entries in all sandboxes {', '.join([en.name for en in group])}" ) for en in group: # skip this d_muO2 stuff if you do note have oxygen if Element("O") in en.composition.elements: d_muO2 = [ { "reaction": str(itr["reaction"]), "chempot": itr["chempot"], "evolution": itr["evolution"], } for itr in phdi.get_element_profile("O", en.composition) ] else: d_muO2 = None en.data["muO2"] = d_muO2 en.data["decomposition_energy"] = phdi.get_e_above_hull(en) # sort out the sandboxes # for each sandbox core+sandbox will both contribute entries all_sbx = [ent.data["_sbxn"] for ent in group] all_sbx = set(chain.from_iterable(all_sbx)) self.logger.debug(f"All sandboxes {', '.join(list(all_sbx))}") for isbx in all_sbx: group_sbx = list( filter( lambda ent: (isbx in ent.data["_sbxn"]) or (ent.data["_sbxn"] == ["core"]), group, ) ) self.logger.debug( f"Grouped entries in sandbox {', '.join([en.name for en in group_sbx])}" ) result = InsertionElectrode(group_sbx, self.working_ion_entry) spacegroup = SpacegroupAnalyzer( result.get_stable_entries(charge_to_discharge=True)[0].structure ) d = result.as_dict_summary() # d['stable_material_ids'] = [entry.entry_id # for entry in result.get_stable_entries()] # d['unstable_material_ids'] = [entry.entry_id # for entry in result.get_unstable_entries()] # d['stability_data'] = {entry.entry_id : entry.data['decomposition_energy'] # for entry in result.get_all_entries()} # d['muO2_data'] = {entry.entry_id : entry.data['muO2'] # for entry in result.get_all_entries()} # sort the ids based on value ids = [entry.entry_id for entry in result.get_all_entries()] lowest_id = sorted(ids, key=lambda x: x.split("-")[-1])[0] d["spacegroup"] = { k: spacegroup._space_group_data[k] for k in sg_fields } if isbx == "core": d["battid"] = lowest_id + "_" + self.working_ion else: d["battid"] = lowest_id + "_" + self.working_ion + "_" + isbx # Only allow one sandbox value for each electrode d["_sbxn"] = [isbx] docs.append(d) return docs
discharge_struc = Structure.from_dict(dict_discharge["structure"]) discharge_energy = dict_discharge["final_energy"] entry_discharge = ComputedStructureEntry(discharge_struc, discharge_energy) discharge_ehull = dict_discharge["e_above_hull"] mpr = MPRester(api_key=API_KEY, host="www.materialsproject.org") entries = mpr.get_entries(result[0][1], inc_structure="final") counter = 0 energies = [] for entry in entries: energies.append(entry.energy_per_atom) working_ion_entry = entries[(energies.index(min(energies)))] cathode = InsertionElectrode([entry_charge, entry_discharge], working_ion_entry) batt_list.append( [result[0], result[1], result[2], charge_struc.formula, charge_ehull, discharge_struc.formula, discharge_ehull, cathode.max_voltage_step, cathode.get_average_voltage(), cathode.get_capacity_vol(), cathode.get_capacity_grav(), cathode.max_delta_volume]) voltage = [] capacity_grav = [] discharge_ehull = [] charge_ehull = [] for working_ion in working_ion_pool: ion_row = []
<<<<<<< HEAD group_sbx = list( filter( lambda ent: (isbx in ent.data["_sbxn"]) or (ent.data["_sbxn"] == ["core"]), group, ) ) self.logger.debug( f"Grouped entries in sandbox {', '.join([en.name for en in group_sbx])}" ) ======= group_sbx = list(filter(lambda ent : (isbx in ent.data['_sbxn']) or (ent.data['_sbxn']==['core']), group)) self.logger.debug(f"Grouped entries in sandbox {isbx} -- {', '.join([en.name for en in group_sbx])}") >>>>>>> master result = InsertionElectrode(group_sbx, self.working_ion_entry) spacegroup = SpacegroupAnalyzer( result.get_stable_entries(charge_to_discharge=True)[0].structure ) d = result.as_dict_summary() # d['stable_material_ids'] = [entry.entry_id # for entry in result.get_stable_entries()] # d['unstable_material_ids'] = [entry.entry_id # for entry in result.get_unstable_entries()] # d['stability_data'] = {entry.entry_id : entry.data['decomposition_energy'] # for entry in result.get_all_entries()} # d['muO2_data'] = {entry.entry_id : entry.data['muO2'] # for entry in result.get_all_entries()}