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(): """ 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 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 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_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 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), ...] """ total_competing_phases = [] 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 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 get_e_above_hull(self): """ Get e_above_hull for this compound Args: allow_negative: whether to calculate negative energy above hull for stable compound Returns: decomposition, energy above hull """ pda = PDAnalyzer(self.pd) (decomp, hull) = pda.get_decomp_and_e_above_hull(self.entry) decomp = [compound.composition.reduced_formula for compound in decomp] return (decomp, hull)
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_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 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 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 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)
a_pbe = PDAnalyzer(pd_pbe) # # visualize quaternary phase diagrams # plotter_lda = PDPlotter(pd_lda,show_unstable = 200) # plotter_lda.show() # plotter_pbe = PDPlotter(pd_pbe,show_unstable = 200) # plotter_pbe.show() # # printing results of the phase diagram data_lda = collections.defaultdict(list) data_pbe = collections.defaultdict(list) print("LDA Phase diagram") for e in entries_lda: decomp, ehull = a_lda.get_decomp_and_e_above_hull(e) formen = pd_lda.get_form_energy_per_atom(e) data_lda["Composition"].append(e.composition.reduced_formula) data_lda["Ehull (meV/atom)"].append(ehull * 13.605698066 * 1000) data_lda["Decomposition"].append(" + ".join( ["%.2f %s" % (v, k.composition.formula) for k, v in decomp.items()])) data_lda["Formation Energy (eV/atom)"].append(formen * 13.605698066) df1 = DataFrame(data_lda, columns=[ "Composition", "Ehull (meV/atom)", "Formation Energy (eV/atom)", "Decomposition" ]) print(df1) print(" ")
# stable labels labels_array = [] for a in phase.stable_entries: a_dict = dict() a_dict["materialid"] = a.entry_id a_dict["name"] = a.name a_dict["formation_energy_per_atom"] = phase.get_form_energy_per_atom(a) a_dict["is_element"] = True for coord, entry in stable.items(): if a.name == entry.name: a_dict["x"] = coord[0] a_dict["y"] = coord[1] # decomp, e_above_hull 받기 decomp, e_above_hull = pda.get_decomp_and_e_above_hull(a) #pretty_decomp = [("{}:{}".format(k.composition.reduced_formula, k.entry_id), round(v, 2)) for k, v in decomp.items()] a_dict["reduced_formula"] = a.composition.reduced_formula a_dict["e_above_hull"] = e_above_hull #a_dict["pretty_decomp"] = pretty_decomp labels_array.append(a_dict) result["stable_labels"] = labels_array # unstable labels labels_array = [] for a in phase.unstable_entries: a_dict = dict() a_dict["materialid"] = a.entry_id a_dict["name"] = a.name a_dict["formation_energy_per_atom"] = phase.get_form_energy_per_atom(a)