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)) # Need more than one level of lithiation to define a electrode material if len(group_sbx) == 1: continue self.logger.debug( f"Grouped entries in sandbox {isbx} -- {', '.join([en.name for en in group_sbx])}" ) try: result = InsertionElectrode(group_sbx, self.working_ion_entry) assert (len(result._stable_entries) > 1) except: self.logger.warn( f"Not able to generate a entries in sandbox {isbx} using the following entires-- {', '.join([en.entry_id for en in group_sbx])}" ) continue spacegroup = SpacegroupAnalyzer( result.get_stable_entries( charge_to_discharge=True)[0].structure) d = result.as_dict_summary() 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
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=PMGJSONDecoder) with open(os.path.join(test_dir, "MgVO_batt.json"), "r") as file: self.entries_MVO = json.load(file, cls=PMGJSONDecoder) with open(os.path.join(test_dir, "Mg_batt.json"), "r") as file: self.entry_Mg = json.load(file, cls=PMGJSONDecoder) 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.to_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.to_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=PMGJSONEncoder) ie = json.loads(json_str, cls=PMGJSONDecoder) 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) 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)
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
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 } <<<<<<< HEAD d["battid"] = lowest_id + "_" + self.working_ion # Only allow one sandbox value for each electrode if isbx != "core": d["_sbxn"] = isbx ======= if isbx == 'core': d['battid'] = lowest_id+'_'+self.working_ion else: d['battid'] = lowest_id+'_'+self.working_ion+'_'+isbx