def e_above(formula, energy): #formula = 'Li6AsN' #energy = -27.53 comp=Composition(formula) target = PDEntry(Composition(formula), energy) elements = list(comp.as_dict().keys()) #print(elements) a = MPRester("API_KEY") #Go to materialsproject.org and create account to get API_KEY #Entries are the basic unit for thermodynamic and other analyses in pymatgen. #This gets all entries belonging to the Ca-C-O system. # entries = a.get_entries_in_chemsys(['Ca', 'C', 'O']) entries = a.get_entries_in_chemsys(elements) #print(entries) pd=PD(entries) # pd.get_decomposition(comp) ehull = pd.get_e_above_hull(target) #plotter = PDPlotter(pd) #plotter.show() return ehull
def test_get_stability(self): entries = self.rester.get_entries_in_chemsys(["Fe", "O"]) modified_entries = [] for entry in entries: # Create modified entries with energies that are 0.01eV higher # than the corresponding entries. if entry.composition.reduced_formula == "Fe2O3": modified_entries.append( ComputedEntry(entry.composition, entry.uncorrected_energy + 0.01, parameters=entry.parameters, entry_id="mod_{}".format(entry.entry_id))) rest_ehulls = self.rester.get_stability(modified_entries) all_entries = entries + modified_entries compat = MaterialsProjectCompatibility() all_entries = compat.process_entries(all_entries) pd = PhaseDiagram(all_entries) for e in all_entries: if str(e.entry_id).startswith("mod"): for d in rest_ehulls: if d["entry_id"] == e.entry_id: data = d break self.assertAlmostEqual(pd.get_e_above_hull(e), data["e_above_hull"])
def test_get_stability(self): entries = self.rester.get_entries_in_chemsys(["Fe", "O"]) modified_entries = [] for entry in entries: # Create modified entries with energies that are 0.01eV higher # than the corresponding entries. if entry.composition.reduced_formula == "Fe2O3": modified_entries.append( ComputedEntry(entry.composition, entry.uncorrected_energy + 0.01, parameters=entry.parameters, entry_id="mod_{}".format(entry.entry_id))) rest_ehulls = self.rester.get_stability(modified_entries) all_entries = entries + modified_entries compat = MaterialsProjectCompatibility() all_entries = compat.process_entries(all_entries) pd = PhaseDiagram(all_entries) for e in all_entries: if str(e.entry_id).startswith("mod"): for d in rest_ehulls: if d["entry_id"] == e.entry_id: data = d break self.assertAlmostEqual(pd.get_e_above_hull(e), data["e_above_hull"])
def get_e_above_hull(formula, energy): atoms = Atoms(formula) full_symbols = atoms.get_chemical_symbols() symbols, counts = np.unique(full_symbols, return_counts=True) # list(set(atoms.get_chemical_symbols())) with MPRester() as m: data = m.get_entries_in_chemsys(symbols, compatible_only=True, property_data=[ 'energy_per_atom', 'unit_cell_formula', 'pretty_formula' ]) PDentries = [] for d in data: d = d.as_dict() PDentries += [PDEntry(d['data']['unit_cell_formula'], d['energy'])] print(d['data']['pretty_formula'], d['energy']) PD = PhaseDiagram(PDentries) # Need to apply MP corrections to +U calculations # MP advanced correction + anion correction #print(energy * 2, energy * 2 + corr_energy * 2) PDE0 = PDEntry(formula, energy) e_hull = PD.get_e_above_hull(PDE0) return e_hull
def get_precursor_library(self): phased = PhaseDiagram(self.entries) if self.confine_to_stables: precursor_library = list(phased.stable_entries) elif self.hull_distance is not None: precursor_library = [ e for e in self.entries if phased.get_e_above_hull(e) <= self.hull_distance ] else: precursor_library = [e for e in self.entries] if self.confine_to_icsd: precursor_library = [ i for i in precursor_library if i.data["icsd_ids"] ] if self.simple_precursors: precursor_library = [ i for i in precursor_library if len(i.composition.elements) < len(self.target_entry.composition.elements) - self.simple_precursors + 1 ] if self.target_entry in precursor_library: precursor_library.pop(precursor_library.index(self.target_entry)) if self.explicit_includes: print("explicitly including: ", self.explicit_includes) for entry_id in self.explicit_includes: try: entry = [ e for e in self.entries if e.entry_id == entry_id ][0] except IndexError: print("Could not find {} in entry list".format(entry_id)) continue if entry not in precursor_library: precursor_library.append(entry) if self.exclude_compositions: precursor_library = [ i for i in precursor_library if i.composition.reduced_formula not in self.exclude_compositions ] self.precursor_library = precursor_library print( "Total # of precursors materials obeying the provided filters: ", len(precursor_library), ) return self.precursor_library
def test_dim1(self): # Ensure that dim 1 PDs can be generated. for el in ["Li", "Fe", "O2"]: entries = [e for e in self.entries if e.composition.reduced_formula == el] pd = PhaseDiagram(entries) self.assertEqual(len(pd.stable_entries), 1) for e in entries: ehull = pd.get_e_above_hull(e) self.assertGreaterEqual(ehull, 0) plotter = PDPlotter(pd) lines, *_ = plotter.pd_plot_data self.assertEqual(lines[0][1], [0, 0])
def recheck_e_above_hull(material_id, key_element): with MPRester(api_key='') as mpr: entry = mpr.get_entry_by_material_id(material_id) pretty_formula = entry.name chemsys = Composition( pretty_formula).chemical_system + '-' + key_element # using GGA and GGA+U mixed scheme as default, namely compatible_only=True entries = mpr.get_entries_in_chemsys(chemsys) phase_diagram = PhaseDiagram(entries) e_above_hull = phase_diagram.get_e_above_hull(entry) # to avoid kind of values -1.77635683940025E-15, and -0.000 after rounded if 0 > e_above_hull >= -phase_diagram.numerical_tol: e_above_hull = 0.0 return (e_above_hull)
class PhaseDiagramTest(unittest.TestCase): def setUp(self): self.entries = EntrySet.from_csv(str(module_dir / "pdentries_test.csv")) self.pd = PhaseDiagram(self.entries) warnings.simplefilter("ignore") def tearDown(self): warnings.simplefilter("default") def test_init(self): # Ensure that a bad set of entries raises a PD error. Remove all Li # from self.entries. entries = filter( lambda e: (not e.composition.is_element) or e.composition.elements[ 0] != Element("Li"), self.entries, ) self.assertRaises(PhaseDiagramError, PhaseDiagram, entries) def test_dim1(self): # Ensure that dim 1 PDs can eb generated. for el in ["Li", "Fe", "O2"]: entries = [ e for e in self.entries if e.composition.reduced_formula == el ] pd = PhaseDiagram(entries) self.assertEqual(len(pd.stable_entries), 1) for e in entries: decomp, ehull = pd.get_decomp_and_e_above_hull(e) self.assertGreaterEqual(ehull, 0) plotter = PDPlotter(pd) lines, stable_entries, unstable_entries = plotter.pd_plot_data self.assertEqual(lines[0][1], [0, 0]) def test_ordering(self): # Test sorting of elements entries = [ ComputedEntry(Composition(formula), 0) for formula in ["O", "N", "Fe"] ] pd = PhaseDiagram(entries) sorted_elements = (Element("Fe"), Element("N"), Element("O")) self.assertEqual(tuple(pd.elements), sorted_elements) entries.reverse() pd = PhaseDiagram(entries) self.assertEqual(tuple(pd.elements), sorted_elements) # Test manual specification of order ordering = [Element(elt_string) for elt_string in ["O", "N", "Fe"]] pd = PhaseDiagram(entries, elements=ordering) self.assertEqual(tuple(pd.elements), tuple(ordering)) def test_stable_entries(self): stable_formulas = [ ent.composition.reduced_formula for ent in self.pd.stable_entries ] expected_stable = [ "Fe2O3", "Li5FeO4", "LiFeO2", "Fe3O4", "Li", "Fe", "Li2O", "O2", "FeO", ] for formula in expected_stable: self.assertTrue(formula in stable_formulas, formula + " not in stable entries!") def test_get_formation_energy(self): stable_formation_energies = { ent.composition.reduced_formula: self.pd.get_form_energy(ent) for ent in self.pd.stable_entries } expected_formation_energies = { "Li5FeO4": -164.8117344866667, "Li2O2": -14.119232793333332, "Fe2O3": -16.574164339999996, "FeO": -5.7141519966666685, "Li": 0.0, "LiFeO2": -7.732752316666666, "Li2O": -6.229303868333332, "Fe": 0.0, "Fe3O4": -22.565714456666683, "Li2FeO3": -45.67166036000002, "O2": 0.0, } for formula, energy in expected_formation_energies.items(): self.assertAlmostEqual(energy, stable_formation_energies[formula], 7) def test_all_entries_hulldata(self): self.assertEqual(len(self.pd.all_entries_hulldata), 492) def test_planar_inputs(self): e1 = PDEntry("H", 0) e2 = PDEntry("He", 0) e3 = PDEntry("Li", 0) e4 = PDEntry("Be", 0) e5 = PDEntry("B", 0) e6 = PDEntry("Rb", 0) pd = PhaseDiagram([e1, e2, e3, e4, e5, e6], map(Element, ["Rb", "He", "B", "Be", "Li", "H"])) self.assertEqual(len(pd.facets), 1) def test_str(self): self.assertIsNotNone(str(self.pd)) def test_get_e_above_hull(self): for entry in self.pd.stable_entries: self.assertLess( self.pd.get_e_above_hull(entry), 1e-11, "Stable entries should have e above hull of zero!", ) for entry in self.pd.all_entries: if entry not in self.pd.stable_entries: e_ah = self.pd.get_e_above_hull(entry) self.assertTrue(isinstance(e_ah, Number)) self.assertGreaterEqual(e_ah, 0) def test_get_equilibrium_reaction_energy(self): for entry in self.pd.stable_entries: self.assertLessEqual( self.pd.get_equilibrium_reaction_energy(entry), 0, "Stable entries should have negative equilibrium reaction energy!", ) def test_get_quasi_e_to_hull(self): for entry in self.pd.unstable_entries: # catch duplicated stable entries if entry.normalize( inplace=False) in self.pd.get_stable_entries_normed(): self.assertLessEqual( self.pd.get_quasi_e_to_hull(entry), 0, "Duplicated stable entries should have negative decomposition energy!", ) else: self.assertGreaterEqual( self.pd.get_quasi_e_to_hull(entry), 0, "Unstable entries should have positive decomposition energy!", ) for entry in self.pd.stable_entries: if entry.composition.is_element: self.assertEqual( self.pd.get_quasi_e_to_hull(entry), 0, "Stable elemental entries should have decomposition energy of zero!", ) else: self.assertLessEqual( self.pd.get_quasi_e_to_hull(entry), 0, "Stable entries should have negative decomposition energy!", ) novel_stable_entry = PDEntry("Li5FeO4", -999) self.assertLess( self.pd.get_quasi_e_to_hull(novel_stable_entry), 0, "Novel stable entries should have negative decomposition energy!", ) novel_unstable_entry = PDEntry("Li5FeO4", 999) self.assertGreater( self.pd.get_quasi_e_to_hull(novel_unstable_entry), 0, "Novel unstable entries should have positive decomposition energy!", ) duplicate_entry = PDEntry("Li2O", -14.31361175) scaled_dup_entry = PDEntry("Li4O2", -14.31361175 * 2) stable_entry = [e for e in self.pd.stable_entries if e.name == "Li2O"][0] self.assertEqual( self.pd.get_quasi_e_to_hull(duplicate_entry), self.pd.get_quasi_e_to_hull(stable_entry), "Novel duplicates of stable entries should have same decomposition energy!", ) self.assertEqual( self.pd.get_quasi_e_to_hull(scaled_dup_entry), self.pd.get_quasi_e_to_hull(stable_entry), "Novel scaled duplicates of stable entries should have same decomposition energy!", ) def test_get_decomposition(self): for entry in self.pd.stable_entries: self.assertEqual( len(self.pd.get_decomposition(entry.composition)), 1, "Stable composition should have only 1 decomposition!", ) dim = len(self.pd.elements) for entry in self.pd.all_entries: ndecomp = len(self.pd.get_decomposition(entry.composition)) self.assertTrue( ndecomp > 0 and ndecomp <= dim, "The number of decomposition phases can at most be equal to the number of components.", ) # Just to test decomp for a ficitious composition ansdict = { entry.composition.formula: amt for entry, amt in self.pd.get_decomposition( Composition("Li3Fe7O11")).items() } expected_ans = { "Fe2 O2": 0.0952380952380949, "Li1 Fe1 O2": 0.5714285714285714, "Fe6 O8": 0.33333333333333393, } for k, v in expected_ans.items(): self.assertAlmostEqual(ansdict[k], v) def test_get_transition_chempots(self): for el in self.pd.elements: self.assertLessEqual(len(self.pd.get_transition_chempots(el)), len(self.pd.facets)) def test_get_element_profile(self): for el in self.pd.elements: for entry in self.pd.stable_entries: if not (entry.composition.is_element): self.assertLessEqual( len(self.pd.get_element_profile(el, entry.composition)), len(self.pd.facets), ) expected = [ { "evolution": 1.0, "chempot": -4.2582781416666666, "reaction": "Li2O + 0.5 O2 -> Li2O2", }, { "evolution": 0, "chempot": -5.0885906699999968, "reaction": "Li2O -> Li2O", }, { "evolution": -1.0, "chempot": -10.487582010000001, "reaction": "Li2O -> 2 Li + 0.5 O2", }, ] result = self.pd.get_element_profile(Element("O"), Composition("Li2O")) for d1, d2 in zip(expected, result): self.assertAlmostEqual(d1["evolution"], d2["evolution"]) self.assertAlmostEqual(d1["chempot"], d2["chempot"]) self.assertEqual(d1["reaction"], str(d2["reaction"])) def test_get_get_chempot_range_map(self): elements = [el for el in self.pd.elements if el.symbol != "Fe"] self.assertEqual(len(self.pd.get_chempot_range_map(elements)), 10) def test_getmu_vertices_stability_phase(self): results = self.pd.getmu_vertices_stability_phase( Composition("LiFeO2"), Element("O")) self.assertAlmostEqual(len(results), 6) test_equality = False for c in results: if (abs(c[Element("O")] + 7.115) < 1e-2 and abs(c[Element("Fe")] + 6.596) < 1e-2 and abs(c[Element("Li")] + 3.931) < 1e-2): test_equality = True self.assertTrue(test_equality, "there is an expected vertex missing in the list") def test_getmu_range_stability_phase(self): results = self.pd.get_chempot_range_stability_phase( Composition("LiFeO2"), Element("O")) self.assertAlmostEqual(results[Element("O")][1], -4.4501812249999997) self.assertAlmostEqual(results[Element("Fe")][0], -6.5961470999999996) self.assertAlmostEqual(results[Element("Li")][0], -3.6250022625000007) def test_get_hull_energy(self): for entry in self.pd.stable_entries: h_e = self.pd.get_hull_energy(entry.composition) self.assertAlmostEqual(h_e, entry.energy) n_h_e = self.pd.get_hull_energy( entry.composition.fractional_composition) self.assertAlmostEqual(n_h_e, entry.energy_per_atom) def test_1d_pd(self): entry = PDEntry("H", 0) pd = PhaseDiagram([entry]) decomp, e = pd.get_decomp_and_e_above_hull(PDEntry("H", 1)) self.assertAlmostEqual(e, 1) self.assertAlmostEqual(decomp[entry], 1.0) def test_get_critical_compositions_fractional(self): c1 = Composition("Fe2O3").fractional_composition c2 = Composition("Li3FeO4").fractional_composition c3 = Composition("Li2O").fractional_composition comps = self.pd.get_critical_compositions(c1, c2) expected = [ Composition("Fe2O3").fractional_composition, Composition("Li0.3243244Fe0.1621621O0.51351349"), Composition("Li3FeO4").fractional_composition, ] for crit, exp in zip(comps, expected): self.assertTrue(crit.almost_equals(exp, rtol=0, atol=1e-5)) comps = self.pd.get_critical_compositions(c1, c3) expected = [ Composition("Fe0.4O0.6"), Composition("LiFeO2").fractional_composition, Composition("Li5FeO4").fractional_composition, Composition("Li2O").fractional_composition, ] for crit, exp in zip(comps, expected): self.assertTrue(crit.almost_equals(exp, rtol=0, atol=1e-5)) def test_get_critical_compositions(self): c1 = Composition("Fe2O3") c2 = Composition("Li3FeO4") c3 = Composition("Li2O") comps = self.pd.get_critical_compositions(c1, c2) expected = [ Composition("Fe2O3"), Composition("Li0.3243244Fe0.1621621O0.51351349") * 7.4, Composition("Li3FeO4"), ] for crit, exp in zip(comps, expected): self.assertTrue(crit.almost_equals(exp, rtol=0, atol=1e-5)) comps = self.pd.get_critical_compositions(c1, c3) expected = [ Composition("Fe2O3"), Composition("LiFeO2"), Composition("Li5FeO4") / 3, Composition("Li2O"), ] for crit, exp in zip(comps, expected): self.assertTrue(crit.almost_equals(exp, rtol=0, atol=1e-5)) # Don't fail silently if input compositions aren't in phase diagram # Can be very confusing if you're working with a GrandPotentialPD self.assertRaises( ValueError, self.pd.get_critical_compositions, Composition("Xe"), Composition("Mn"), ) # For the moment, should also fail even if compositions are in the gppd # because it isn't handled properly gppd = GrandPotentialPhaseDiagram(self.pd.all_entries, {"Xe": 1}, self.pd.elements + [Element("Xe")]) self.assertRaises( ValueError, gppd.get_critical_compositions, Composition("Fe2O3"), Composition("Li3FeO4Xe"), ) # check that the function still works though comps = gppd.get_critical_compositions(c1, c2) expected = [ Composition("Fe2O3"), Composition("Li0.3243244Fe0.1621621O0.51351349") * 7.4, Composition("Li3FeO4"), ] for crit, exp in zip(comps, expected): self.assertTrue(crit.almost_equals(exp, rtol=0, atol=1e-5)) # case where the endpoints are identical self.assertEqual(self.pd.get_critical_compositions(c1, c1 * 2), [c1, c1 * 2]) def test_get_composition_chempots(self): c1 = Composition("Fe3.1O4") c2 = Composition("Fe3.2O4.1Li0.01") e1 = self.pd.get_hull_energy(c1) e2 = self.pd.get_hull_energy(c2) cp = self.pd.get_composition_chempots(c1) calc_e2 = e1 + sum(cp[k] * v for k, v in (c2 - c1).items()) self.assertAlmostEqual(e2, calc_e2) def test_get_all_chempots(self): c1 = Composition("Fe3.1O4") c2 = Composition("FeO") cp1 = self.pd.get_all_chempots(c1) cpresult = { Element("Li"): -4.077061954999998, Element("Fe"): -6.741593864999999, Element("O"): -6.969907375000003, } for elem, energy in cpresult.items(): self.assertAlmostEqual(cp1["Fe3O4-FeO-LiFeO2"][elem], energy) cp2 = self.pd.get_all_chempots(c2) cpresult = { Element("O"): -7.115354140000001, Element("Fe"): -6.5961471, Element("Li"): -3.9316151899999987, } for elem, energy in cpresult.items(): self.assertAlmostEqual(cp2["FeO-LiFeO2-Fe"][elem], energy) def test_to_from_dict(self): # test round-trip for other entry types such as ComputedEntry entry = ComputedEntry("H", 0.0, 0.0, entry_id="test") pd = PhaseDiagram([entry]) d = pd.as_dict() pd_roundtrip = PhaseDiagram.from_dict(d) self.assertEqual(pd.all_entries[0].entry_id, pd_roundtrip.all_entries[0].entry_id)
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
# getting Composition Object comp = Composition(phase) # getting entry for PD Object entry = PDEntry(comp, computed_phases[phase]) # building list of entries entries.append(entry) # getting PD from list of entries pd = PhaseDiagram(entries) # get distance from convex hull for cubic phase comp = Composition('NaNbO3') energy = -38.26346361 entry = PDEntry(comp, energy) cubic_instability = pd.get_e_above_hull(entry) pd_dict = pd.as_dict() # Getting Plot plt = PDPlotter(pd, show_unstable=False) # you can also try show_unstable=True #plt_data = plt.pd_plot_data # getting plot for chem potential - variables 'fontsize' for labels size and 'plotsize' for fig size have been added (not present in original pymatgen) to get_chempot_range_map_plot function chem_pot_plot = plt.get_chempot_range_map_plot( [Element("Na"), Element("Nb")], fontsize=14, plotsize=1.5) #plt.write_image("chem_pot_{}.png".format('-'.join(system)), "png") chem_pot_plot.savefig(f'chem_pot_{system_name}.png') # save figure # getting plot for PD - variables 'fontsize' for labels size and plotsize for fig size have been added (not present in original pymatgen) to get_plot function pd_plot = plt.get_plot(label_stable=True, fontsize=24, plotsize=3)
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
mpr = MPRester('9RTlN5ZOXst6PAdS') strucs = [] if options.id is None: system = parse_system(options.element) if type(system) is not list: mp_entries = mpr.get_entries(system) else: mp_entries = mpr.get_entries_in_chemsys(system) pd = PhaseDiagram(mp_entries) if options.dimension is None: options.dimension = len(system) for entry in mp_entries: accept = False if type(system) is list: if len(entry.composition) >= options.dimension: eng = pd.get_e_above_hull(entry) if eng <= options.cutoff: accept = True else: eng = entry.energy_per_atom accept = True if accept: struc = output_struc(entry, eng, tol=1e-2) strucs.append(struc) else: strucs.append(mpr.get_structure_by_material_id(options.id)) if options.format == 'poscar': filename = 'MPR.vasp' else: filename = 'MPR.cif'