def setUp(self): (elements, entries) = PDEntryIO.from_csv( os.path.join(module_dir, "pdentries_test.csv")) self.pd = PhaseDiagram(entries) self.plotter = PDPlotter(self.pd, show_unstable=True) entrieslio = [ e for e in entries if len(e.composition) < 3 and ("Fe" not in e.composition) ] self.pd_formation = PhaseDiagram(entrieslio) self.plotter_formation = PDPlotter(self.pd_formation, show_unstable=True) entries.append(PDEntry("C", 0)) self.pd3d = PhaseDiagram(entries) self.plotter3d = PDPlotter(self.pd3d, show_unstable=True)
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) a = PDAnalyzer(pd) 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(a.get_e_above_hull(e), data["e_above_hull"])
def get_competing_phases(): """ Collect the species to which the material might decompose to. Returns: A list of phases as tuples formatted as [(formula_1, Materials_Project_ID_1), (formula_2, Materials_Project_ID_2), ...] """ composition = Structure.from_file('POSCAR').composition try: energy = Vasprun('vasprun.xml').final_energy except: energy = 100 # The function can work without a vasprun.xml entries = MPR.get_entries_in_chemsys([elt.symbol for elt in composition]) my_entry = ComputedEntry(composition, energy) entries.append(my_entry) pda = PDAnalyzer(PhaseDiagram(entries)) decomp = pda.get_decomp_and_e_above_hull(my_entry, allow_negative=True) competing_phases = [(entry.composition.reduced_formula, entry.entry_id) for entry in decomp[0]] return competing_phases
def test_1d_pd(self): entry = PDEntry('H', 0) pd = PhaseDiagram([entry]) pda = PDAnalyzer(pd) decomp, e = pda.get_decomp_and_e_above_hull(PDEntry('H', 1)) self.assertAlmostEqual(e, 1) self.assertAlmostEqual(decomp[entry], 1.0)
def get_competing_phases_new(structure): """ Collect the species to which the 2D materials might decompose to. Since a lot of 2D materials with similar compositions will have the same competing phases, duplicates aren't counted. """ total_competing_phases = [] composition = structure.composition energy = 100 my_entry = ComputedEntry(composition, energy) # 2D material entries = MPR.get_entries_in_chemsys( elements=[elt.symbol for elt in composition]) entries.append(my_entry) # 2D material pda = PDAnalyzer(PhaseDiagram(entries)) decomp = pda.get_decomp_and_e_above_hull(my_entry, allow_negative=True) competing_phases = [(entry.composition.reduced_formula, entry.entry_id) for entry in decomp[0]] # Keep a running list of all unique competing phases, since in # high throughput 2D searches there is usually some overlap in # competing phases for different materials. for specie in competing_phases: if specie not in total_competing_phases: total_competing_phases.append(specie) return total_competing_phases
def get_hull_distance(competing_phase_directory='../competing_phases'): """ Calculate the material's distance to the thermodynamic hull, based on species in the Materials Project database. Args: competing_phase_directory (str): absolute or relative path to the location where your competing phases have been relaxed. The default expectation is that they are stored in a directory named 'competing_phases' at the same level as your material's relaxation directory. Returns: float. distance (eV/atom) between the material and the hull. """ finished_competitors = {} original_directory = os.getcwd() # Determine which competing phases have been relaxed in the current # framework and store them in a dictionary ({formula: entry}). if os.path.isdir(competing_phase_directory): os.chdir(competing_phase_directory) for comp_dir in [ dir for dir in os.listdir(os.getcwd()) if os.path.isdir(dir) and is_converged(dir) ]: vasprun = Vasprun('{}/vasprun.xml'.format(comp_dir)) composition = vasprun.final_structure.composition energy = vasprun.final_energy finished_competitors[comp_dir] = ComputedEntry(composition, energy) os.chdir(original_directory) else: raise ValueError('Competing phase directory does not exist.') composition = Structure.from_file('POSCAR').composition try: energy = Vasprun('vasprun.xml').final_energy except: raise ValueError( 'This directory does not have a converged vasprun.xml') my_entry = ComputedEntry(composition, energy) # 2D material entries = MPR.get_entries_in_chemsys([elt.symbol for elt in composition]) # If the energies of competing phases have been calculated in # the current framework, put them in the phase diagram instead # of the MP energies. for i in range(len(entries)): formula = entries[i].composition.reduced_formula if formula in finished_competitors: entries[i] = finished_competitors[formula] else: entries[i] = ComputedEntry(entries[i].composition, 100) entries.append(my_entry) # 2D material pda = PDAnalyzer(PhaseDiagram(entries)) decomp = pda.get_decomp_and_e_above_hull(my_entry, allow_negative=True) return decomp[1]
def build_corrected_pd(entries): """build_corrected_pd Builds a PD with entries using Mat.Proj. compatibility. :param entries: List of ComputedEntry objects :return: A Phase diagram object """ corrected = MaterialsProjectCompatibility().process_entries(entries) return PhaseDiagram(corrected)
def process_item(self, item): """ Process the list of entries into a phase diagram Args: item (set(entry)): a list of entries to process into a phase diagram Returns: [dict]: a list of thermo dictionaries to update thermo with """ entries = self.__compat.process_entries(item) try: pd = PhaseDiagram(entries) analyzer = PDAnalyzer(pd) docs = [] for e in entries: (decomp, ehull) = \ analyzer.get_decomp_and_e_above_hull(e) d = {"material_id": e.entry_id} d["thermo"] = {} d["thermo"][ "formation_energy_per_atom"] = pd.get_form_energy_per_atom( e) d["thermo"]["e_above_hull"] = ehull d["thermo"]["is_stable"] = e in stable_entries d["thermo"][ "eq_reaction_e"] = analyzer.get_equilibrium_reaction_energy( e) d["thermo"]["decomposes_to"] = [{ "material_id": de.entry_id, "formula": de.composition.formula, "amount": amt } for de, amt in decomp.items()] docs.append(d) except PhaseDiagramError as p: self.__logger.warning("Phase diagram error: {}".format(p)) return [] return docs
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 mke_pour_ion_entr(mtnme, ion_dict, stable_solids_minus_h2o, ref_state, entries_aqcorr, ref_dict): """ """ #| - mke_pour_ion_entr from pymatgen import Element # Accesses properties of element from pymatgen.core.ion import Ion from pymatgen.phasediagram.maker import PhaseDiagram from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry from pd_make import ref_entry_find, ref_entry_stoich pd = PhaseDiagram(entries_aqcorr) ref_entry = ref_entry_find(stable_solids_minus_h2o, ref_state) ref_stoich_fact = ref_entry_stoich(ref_entry) ## Calculate DFT reference E for ions (Persson et al, PRB (2012)) dft_for_e=pd.get_form_energy(ref_entry)/ref_stoich_fact # DFT formation E, normalized by composition "factor" ion_correction_1 = dft_for_e-ref_dict[ref_state] # Difference of DFT form E and exp for E of reference el = Element(mtnme) pbx_ion_entries_1 = [] for id in ion_dict: comp = Ion.from_formula(id['Name']) # Ion name-> Ion comp name (ex. Fe[3+] -> Ion: Fe1 +3) # comp.composition[el] : number of Fe atoms in ion num_el_ref = (ref_entry.composition[el]) / ref_stoich_fact # number of element atoms in reference factor = comp.composition[el] / num_el_ref # Stoicheometric factor for ionic correction # (i.e. Fe2O3 ref but calc E for Fe[2+] ion) energy = id['Energy'] + ion_correction_1 * factor #TEMP_PRINT if id['Name']=='Pd[2+]': energy = 123 # print id['Name'] pbx_entry_ion = PourbaixEntry(IonEntry(comp, energy)) pbx_entry_ion.name = id['Name'] pbx_ion_entries_1.append(pbx_entry_ion) return pbx_ion_entries_1
def get_deco(e, pda): """get_deco Gets the non-stoichiometric decomposition products of e. :param e: Entry we want the decomposition of. :param pda: PDAnalzyer containing e. """ e_c = e.composition.reduced_composition shifted_entries = [copy.deepcopy(e) for e in pda._pd.all_entries] for o_e in shifted_entries: if o_e.composition.reduced_composition == e_c: o_e.uncorrected_energy += 10.0 new_pd = PhaseDiagram(shifted_entries) new_pda = PDAnalyzer(new_pd) decomp = new_pda.get_decomposition(e_c) return decomp
def build_complete_pd(f, calc_list): """build_complete_pd Builds a PD including appropriate local calcs. :param f: Formula for which we seek to construct a PD. :param calc_list: A list of folders containing local calculations. :return: A Phasediagram object. """ entries = pd_tools.get_pruned_chemsys(f) csys = [el for el in Composition(f).as_dict()] for d in calc_list: data_dir = root_dir + "/" + d + "/relax_final" if set(eles_in_calc(data_dir)).issubset(set(csys)): entries.append(create_entry(data_dir)) entries_proc = MaterialsProjectCompatibility().process_entries(entries) return PhaseDiagram(entries_proc)
def __init__(self, entries, working_ion_entry): """ Create a new InsertionElectrode. Args: entries: A list of ComputedStructureEntries (or subclasses) representing the different topotactic states of the battery, e.g. TiO2 and LiTiO2. working_ion_entry: A single ComputedEntry or PDEntry representing the element that carries charge across the battery, e.g. Li. """ self._entries = entries self._working_ion = working_ion_entry.composition.elements[0] self._working_ion_entry = working_ion_entry #Prepare to make phase diagram: determine elements and set their energy #to be very high elements = set() for entry in entries: elements.update(entry.composition.elements) #Set an artificial energy for each element for convex hull generation element_energy = max([entry.energy_per_atom for entry in entries]) + 10 pdentries = [] pdentries.extend(entries) pdentries.extend([PDEntry(Composition({el:1}), element_energy) for el in elements]) #Make phase diagram to determine which entries are stable vs. unstable pd = PhaseDiagram(pdentries) lifrac = lambda e: e.composition.get_atomic_fraction(self._working_ion) #stable entries ordered by amount of Li asc self._stable_entries = tuple(sorted([e for e in pd.stable_entries if e in entries], key=lifrac)) #unstable entries ordered by amount of Li asc self._unstable_entries = tuple(sorted([e for e in pd.unstable_entries if e in entries], key=lifrac)) #create voltage pairs self._vpairs = tuple([InsertionVoltagePair(self._stable_entries[i], self._stable_entries[i + 1], working_ion_entry) for i in range(len(self._stable_entries) - 1)])
def from_composition_and_entries(comp, entries_in_chemsys, working_ion_symbol="Li"): """ Convenience constructor to make a ConversionElectrode from a composition and all entries in a chemical system. Args: comp: Starting composition for ConversionElectrode, e.g., Composition("FeF3") entries_in_chemsys: Sequence containing all entries in a chemical system. E.g., all Li-Fe-F containing entries. working_ion_symbol: Element symbol of working ion. Defaults to Li. """ pd = PhaseDiagram(entries_in_chemsys) return ConversionElectrode.from_composition_and_pd(comp, pd, working_ion_symbol)
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) a = PDAnalyzer(pd) for e in entries: decomp, ehull = a.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 get_pd(self): """ get the phase diagram object for this compound Returns: phase diagram, entry """ #make MP compatible entry from vasprun entry = self.vasprun.get_computed_entry() compat = MaterialsProjectCompatibility() entry = compat.process_entry(entry) el = [specie.symbol for specie in entry.composition.keys()] with MPRester(api_key=API_KEY) as mpr: entries = mpr.get_entries_in_chemsys(el) entries.append(entry) pd = PhaseDiagram(entries) return pd, entry
def get_mu_range(mpid, ext_elts=[]): if 'hse' in mpid: mpid = mpid.split('_')[0] try: entry = m.get_entry_by_material_id(mpid) in_MP = True except: from high_throughput.defects.database import TasksOperater in_MP = False TO = TasksOperater() id_ = TO.groups['bulk'][mpid][0] rec = TO.collection.find_one({'_id':id_},['output']) stru_tmp =Structure.from_dict(rec['output']['crystal']) energy = rec['output']['final_energy'] entry = PDEntry(stru_tmp.composition, energy) elts = [i.symbol for i in entry.composition.elements] for i in ext_elts: elts.append(i) entries = m.get_entries_in_chemsys(elts) if not in_MP: entries.append(entry) for entry in entries: entry.correction = 0.0 pd=PhaseDiagram(entries) pda=PDAnalyzer(pd) chempots={} decompositions=pda.get_decomposition(entry.composition).keys() decomposition_inds=[pd.qhull_entries.index(entry) for entry in decompositions] facets_around=[] for facet in pd.facets: is_facet_around=True for ind in decomposition_inds: if ind not in facet: is_facet_around=False if is_facet_around==True: facets_around.append(facet) for facet in facets_around: s=[] for ind in facet: s.append(str(pd.qhull_entries[ind].name)) s.sort() chempots['-'.join(s)]=pda.get_facet_chempots(facet) chempots={i:{j.symbol:chempots[i][j] for j in chempots[i]} for i in chempots} return chempots
def main(): """ Main function. """ # Read the calculation results into a ComputedEntry. entl = VaspToComputedEntryDrone().assimilate(sys.argv[1]) # Check if our local calculation is compatible with MP. if MaterialsProjectCompatibility().process_entry(entl) is None: print("Calculation not compatible with MP.") sys.exit(0) # Get other entries sharing a chemical system with the results. chemsys = [ele for ele in entl.composition.as_dict()] with MPRester() as mpr: chemsys_entries = mpr.get_entries_in_chemsys(chemsys) # Append our local calculation to the list of entries. chemsys_entries.append(entl) # Process the entries. p_e = MaterialsProjectCompatibility().process_entries(chemsys_entries) # Build a phase diagram and an analyzer for it. p_d = PhaseDiagram(p_e) pda = PDAnalyzer(p_d) # Scan stable entries for our calculation. for ent in p_d.stable_entries: if ent.entry_id is None: print(str(ent.composition.reduced_formula) + " 0.0") sys.exit(0) # Scan unstable entries for our calculation and print decomposition. for ent in p_d.unstable_entries: if ent.entry_id is None: dco, ehull = pda.get_decomp_and_e_above_hull(ent) pretty_dc = [("{}:{}".format(k.composition.reduced_formula, k.entry_id), round(v, 2)) for k, v in dco.items()] print( str(ent.composition.reduced_formula) + " %.3f" % ehull + " " + str(pretty_dc))
def stable_entr(entries_aqcorr): """ Evaluate a entries in list for stability and discard unstable entries Remove H2, O2, H2O, and H2O2 from the list Calculate the formation using the species in the chemical ensemble Args: entries_aqcorr: List of entries, usually they have been run through the aqueous compatibility module """ #| - stable_entr from pymatgen.analysis.pourbaix.entry import PourbaixEntry from pymatgen.phasediagram.maker import PhaseDiagram ## Generate phase diagram to consider only solid entries stable in water pd = PhaseDiagram(entries_aqcorr) stable_solids = pd.stable_entries stable_solids_minus_h2o = [entry for entry in stable_solids if entry.composition.reduced_formula not in ["H2", "O2", "H2O", "H2O2"]] return stable_solids_minus_h2o
def get_equilibrium_reaction_energy(self, entry): """ Provides the reaction energy of a stable entry from the neighboring equilibrium stable entries (also known as the inverse distance to hull). Args: entry: A PDEntry like object Returns: Equilibrium reaction energy of entry. Stable entries should have equilibrium reaction energy <= 0. """ if entry not in self._pd.stable_entries: raise ValueError("Equilibrium reaction energy is available only " "for stable entries.") if entry.is_element: return 0 entries = [e for e in self._pd.stable_entries if e != entry] modpd = PhaseDiagram(entries, self._pd.elements) analyzer = PDAnalyzer(modpd) return analyzer.get_decomp_and_e_above_hull(entry, allow_negative=True)[1]
def get_equilibrium_reaction_energy(self): """ Adapted from pymatgen. Only work if entry is stable(hull = 0) Provides the reaction energy of a stable entry from the neighboring equilibrium stable entries (also known as the inverse distance to hull). Returns: Equilibrium reaction energy of entry. Stable entries should have equilibrium reaction energy <= 0. """ if self.entry not in self.pd.stable_entries: raise ValueError("Equilibrium reaction energy is available only " "for stable entries.") entries = [e for e in self.pd.stable_entries if e != self.entry ] #all stable entries without this stable entry modpd = PhaseDiagram(entries, self.pd.elements) analyzer = PDAnalyzer(modpd) (decomp, hull) = analyzer.get_decomp_and_e_above_hull(self.entry, allow_negative=True) decomp = [compound.composition.reduced_formula for compound in decomp] return (decomp, hull)
def get_lowest_decomposition(self, composition): """ Get the decomposition leading to lowest cost Args: composition: Composition as a pymatgen.core.structure.Composition Returns: Decomposition as a dict of {Entry: amount} """ entries_list = [] elements = [e.symbol for e in composition.elements] for i in range(len(elements)): for combi in itertools.combinations(elements, i + 1): chemsys = [Element(e) for e in combi] x = self.costdb.get_entries(chemsys) entries_list.extend(x) try: pd = PhaseDiagram(entries_list) return PDAnalyzer(pd).get_decomposition(composition) except IndexError: raise ValueError("Error during PD building; most likely, " "cost data does not exist!")
def form_e(stable_solids_minus_h2o, entries_aqcorr, gas_gibbs=True): """ Calculate the formation energy for the entries in stable_solids_minus_h2o Reduce by stoicheometric factor if applicable (ex. Fe4O4) Args: stable_solids_minus_h2o: list of stable solids without O2, H2O, H2, and H2O2 (from stable_entr) entries_aqcorr: entries list before being modified by stable_entr """ #| - form_e #| - Imported Modules from pymatgen.analysis.pourbaix.entry import PourbaixEntry from pymatgen.phasediagram.maker import PhaseDiagram from entry_methods import base_atom from energy_scheme import ref_atoms_dict #__| ref_atom_energies = ref_atoms_dict() e_o = ref_atom_energies['e_o'] e_h = ref_atom_energies['e_h'] pd = PhaseDiagram(entries_aqcorr) base_at = base_atom(stable_solids_minus_h2o) d = {} for i in stable_solids_minus_h2o: if i.name in base_at: d[i.name] = i.energy_per_atom def form_energy(entry, solid_ref_energy_dict, gas_gibbs=True): """ Calculates the formation energy of an entry relative to the VASP energies of the reference atoms. Gibbs/entropy corrections for the gas phase are optionable Args: entry: Entry whose formation energy will be calculated solid_ref_energy_dict: Dictionary of reference atom energies gas_gibbs: Whether the gas phase reference atoms will have an entropic correction """ if gas_gibbs==True: ref_dict = {} ref_dict['O'] = e_o-0.3167 ref_dict['H'] = e_h-0.36218 elif gas_gibbs==False: ref_dict = {} ref_dict['O'] = e_o ref_dict['H'] = e_h z = ref_dict.copy() z.update(solid_ref_energy_dict) ref_dict = z elem_dict = entry.composition.get_el_amt_dict() entry_e = entry.energy for elem in entry.composition.elements: elem_num = elem_dict[elem.symbol] entry_e = entry_e - elem_num*ref_dict[elem.symbol] return entry_e pbx_solid_entries = [] for entry in stable_solids_minus_h2o: pbx_entry = PourbaixEntry(entry) pbx_entry.g0_replace(form_energy(entry, d, gas_gibbs=gas_gibbs)) #Replace E with form E relative to ref elements # pbx_entry.g0_replace(pd.get_form_energy(entry)) #Replace E with form E relative to ref elements pbx_entry.reduced_entry() #Reduces parameters by stoich factor (ex. Li2O2 -> LiO) pbx_solid_entries.append(pbx_entry) return pbx_solid_entries
comp = Composition(extracted) computed_entry = ComputedEntry(comp, energy, entry_id=compound["materialId"], parameters="param") Computed_entries.append(computed_entry) except KeyError: pass result = dict() try: # Create phase diagram! with warnings.catch_warnings(): warnings.simplefilter("ignore") phase = PhaseDiagram(Computed_entries) except Exception as e: result["error"] = str(e) json_dir = output_Path + "/" + "output.json" with open(json_dir, "w") as outfile: json.dump(result, outfile) print(result) exit() # Plot! plotter = PDPlotter(phase, show_unstable=True) #plotter.show() lines, stable, unstable = plotter.pd_plot_data ### NEED_TO_CHANGE ###
def setUp(self): module_dir = os.path.dirname(os.path.abspath(__file__)) (self.elements, self.entries) = \ PDEntryIO.from_csv(os.path.join(module_dir, "pdentries_test.csv")) self.pd = PhaseDiagram(self.entries)
class PhaseDiagramTest(unittest.TestCase): def setUp(self): module_dir = os.path.dirname(os.path.abspath(__file__)) (self.elements, self.entries) = \ PDEntryIO.from_csv(os.path.join(module_dir, "pdentries_test.csv")) self.pd = PhaseDiagram(self.entries) 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, self.elements) 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) a = PDAnalyzer(pd) for e in entries: decomp, ehull = a.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_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 setUp(self): module_dir = os.path.dirname(os.path.abspath(__file__)) (elements, entries) = PDEntryIO.from_csv( os.path.join(module_dir, "pdentries_test.csv")) self.pd = PhaseDiagram(entries) self.analyzer = PDAnalyzer(self.pd)
enpbe.append(float(y)) term_comp = [ Composition(names[7]), Composition(names[11]), Composition(names[32]) ] # creating entries from for the LDA phase diagram entries_lda = [] for i in range(len(names)): # entries_lda.append(PDEntry(names[i],enlda[i], names[i], "LDA")) entries_lda.append(PDEntry(names[i], enlda[i], " ", "LDA")) # creating the phase diagram for LDA pd_lda = PhaseDiagram(entries_lda) cpd_lda = CompoundPhaseDiagram(entries_lda, term_comp, normalize_terminal_compositions=True) a_lda = PDAnalyzer(pd_lda) # creating entries from for the PBE phase diagram entries_pbe = [] for i in range(len(names)): # entries_pbe.append(PDEntry(names[i],enpbe[i], names[i], "PBE")) entries_pbe.append(PDEntry(names[i], enpbe[i], " ", "PBE")) # creating the phase diagram for PBE pd_pbe = PhaseDiagram(entries_pbe) cpd_pbe = CompoundPhaseDiagram(entries_pbe, term_comp,
] return relevant_entries def find_entry_index(formula, all_entries): entry_index = [ all_entries.index(entry) for entry in all_entries if entry.composition.reduced_formula == Composition( formula).reduced_formula ] return entry_index rester = MPRester( '5TxDLF4Iwa7rGcAl') #Generate your own key from materials project.. mp_entries = rester.get_entries_in_chemsys(["Li", "Fe", "O", "S"]) pd = PhaseDiagram(mp_entries) plotter = PDPlotter(pd) analyzer = PDAnalyzer(pd) li_entries = [e for e in mp_entries if e.composition.reduced_formula == "Li"] uli0 = min(li_entries, key=lambda e: e.energy_per_atom).energy_per_atom el_profile = analyzer.get_element_profile(Element("Li"), Composition("Li2FeSO")) for i, d in enumerate(el_profile): voltage = -(d["chempot"] - uli0) print("Voltage: %s V" % voltage) print(d["reaction"]) print("")
class PhaseDiagramTest(unittest.TestCase): def setUp(self): module_dir = os.path.dirname(os.path.abspath(__file__)) (self.elements, self.entries) = \ PDEntryIO.from_csv(os.path.join(module_dir, "pdentries_test.csv")) self.pd = PhaseDiagram(self.entries) 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, self.elements) 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) a = PDAnalyzer(pd) for e in entries: decomp, ehull = a.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_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))
pass def get_most_stable_entry(formula): relevant_entries = [ entry for entry in Computed_entries if entry.composition.reduced_formula == Composition( formula).reduced_formula ] relevant_entries = sorted(relevant_entries, key=lambda e: e.energy_per_atom) # print relevant_entries return relevant_entries[0] phase = PhaseDiagram(Computed_entries) form_energy = dict() stable_formula = list() error = dict() for each_formula in formula_list: try: stable_ent = get_most_stable_entry(each_formula) except IndexError: error["error"] = "No structure with that formula" json_dir = output_path + "/" + "output.json" with open(json_dir, "w") as outfile: json.dump(error, outfile) print(error) exit() # print stable_ent.name, phase.get_form_energy(stable_ent) (each_comp, each_factor