def assimilate(self, path): files = os.listdir(path) if "relax1" in files and "relax2" in files: filepath = glob.glob(os.path.join(path, "relax2", "vasprun.xml*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] elif len(vasprun_files) > 1: # Since multiple files are ambiguous, we will always read # the one that it the last one alphabetically. filepath = sorted(vasprun_files)[-1] warnings.warn("%d vasprun.xml.* found. %s is being parsed." % (len(vasprun_files), filepath)) try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug("error in {}: {}".format(filepath, ex)) return None entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) entry.parameters["history"] = _get_transformation_history(path) return entry
def get_chempot_limits(self): """ Returns atomic chempots from bulk_composition based on data in the materials project database. This is abstractly handled in the ChemPotAnalyzer Note to user: If personal phase diagram desired, option exists in the pycdt.core.chemical_potentials to setup, run and parse personal phase diagrams for purposes of chemical potentials """ logger = logging.getLogger(__name__) if self._mpid: cpa = MPChemPotAnalyzer( mpid = self._mpid, sub_species = self._substitution_species, mapi_key = self._mapi_key) else: bulkvr = Vasprun(os.path.join( self._root_fldr, "bulk", "vasprun.xml"), parse_potcar_file=False) if not bulkvr: msg = "Could not fetch computed entry for atomic chempots!" logger.warning(msg) raise ValueError(msg) cpa = MPChemPotAnalyzer( bulk_ce=bulkvr.get_computed_entry(), sub_species = self._substitution_species, mapi_key = self._mapi_key) chem_lims = cpa.analyze_GGA_chempots() return chem_lims
def assimilate(self, path): files = os.listdir(path) if "relax1" in files and "relax2" in files: filepath = glob.glob(os.path.join(path, "relax2", "vasprun.xml*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] elif len(vasprun_files) > 1: # Since multiple files are ambiguous, we will always read # the one that it the last one alphabetically. filepath = sorted(vasprun_files)[-1] warnings.warn("%d vasprun.xml.* found. %s is being parsed." % (len(vasprun_files), filepath)) try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug("error in {}: {}".format(filepath, ex)) return None entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) # entry.parameters["history"] = _get_transformation_history(path) return entry
def assimilate(self, path): """ Assimilate data in a directory path into a ComputedEntry object. Args: path: directory path Returns: ComputedEntry """ files = os.listdir(path) if "relax1" in files and "relax2" in files: filepath = glob.glob(os.path.join(path, "relax2", "vasprun.xml*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] elif len(vasprun_files) > 1: # Since multiple files are ambiguous, we will always read # the one that it the last one alphabetically. filepath = sorted(vasprun_files)[-1] warnings.warn(f"{len(vasprun_files)} vasprun.xml.* found. {filepath} is being parsed.") try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug(f"error in {filepath}: {ex}") return None entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) # entry.parameters["history"] = _get_transformation_history(path) return entry
def assimilate(self, path): files = os.listdir(path) if "relax1" in files and "relax2" in files: filepath = glob.glob(os.path.join(path, "relax2", "vasprun.xml*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] elif len(vasprun_files) > 1: """ This is a bit confusing, since there maybe be multi-steps. By default, assimilate will try to find a file simply named vasprun.xml, vasprun.xml.bz2, or vasprun.xml.gz. Failing which it will try to get a relax2 from an aflow style run if possible. Or else, a randomly chosen file containing vasprun.xml is chosen. """ for fname in vasprun_files: if os.path.basename(fname) in ["vasprun.xml", "vasprun.xml.gz", "vasprun.xml.bz2"]: filepath = fname break if re.search("relax2", fname): filepath = fname break filepath = fname try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug("error in {}: {}".format(filepath, ex)) return None entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) entry.parameters["history"] = _get_transformation_history(path) return entry
def assimilate(self, path): files = os.listdir(path) if "relax1" in files and "relax2" in files: filepath = glob.glob(os.path.join(path, "relax2", "vasprun.xml*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] elif len(vasprun_files) > 1: """ This is a bit confusing, since there maybe be multi-steps. By default, assimilate will try to find a file simply named vasprun.xml, vasprun.xml.bz2, or vasprun.xml.gz. Failing which it will try to get a relax2 from an aflow style run if possible. Or else, a randomly chosen file containing vasprun.xml is chosen. """ for fname in vasprun_files: if os.path.basename(fname) in ["vasprun.xml", "vasprun.xml.gz", "vasprun.xml.bz2"]: filepath = fname break if re.search(r"relax2", fname): filepath = fname break filepath = fname try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug("error in {}: {}".format(filepath, ex)) return None entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) entry.parameters["history"] = _get_transformation_history(path) return entry
def test_properties(self): filepath = os.path.join(test_dir, 'vasprun.xml.nonlm') vasprun = Vasprun(filepath, parse_potcar_file=False) orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[ 0]].keys()) self.assertIn(OrbitalType.s, orbs) filepath = os.path.join(test_dir, 'vasprun.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) #Test NELM parsing. self.assertEqual(vasprun.parameters["NELM"], 60) #test pdos parsing pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]] self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026) self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012) self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, )) filepath2 = os.path.join(test_dir, 'lifepo4.xml') vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True, parse_potcar_file=False) totalscsteps = sum([len(i['electronic_steps']) for i in vasprun.ionic_steps]) self.assertEqual(29, len(vasprun.ionic_steps)) self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps)) self.assertEqual(vasprun.lattice, vasprun.lattice_rec.reciprocal_lattice) for i, step in enumerate(vasprun.ionic_steps): self.assertEqual(vasprun.structures[i], step["structure"]) self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][ "structure"] for i in range(len(vasprun.ionic_steps))])) self.assertEqual(308, totalscsteps, "Incorrect number of energies read from vasprun.xml") self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"], vasprun.atomic_symbols) self.assertEqual(vasprun.final_structure.composition.reduced_formula, "LiFe4(PO4)4") self.assertIsNotNone(vasprun.incar, "Incar cannot be read") self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read") self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7) self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4) expectedans = (2.539, 4.0906, 1.5516, False) (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties self.assertAlmostEqual(gap, expectedans[0]) self.assertAlmostEqual(cbm, expectedans[1]) self.assertAlmostEqual(vbm, expectedans[2]) self.assertEqual(direct, expectedans[3]) self.assertFalse(vasprun.is_hubbard) self.assertEqual(vasprun.potcar_symbols, ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003', 'PAW_PBE O 08Apr2002']) self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints, "Actual kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints_weights, "Actual kpoints weights cannot be read") for atomdoses in vasprun.pdos: for orbitaldos in atomdoses: self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read") # test skipping ionic steps. vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False) self.assertEqual(vasprun_skip.nionic_steps, 29) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) self.assertEqual(len(vasprun_skip.ionic_steps), len(vasprun_skip.structures)) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) # Check that nionic_steps is preserved no matter what. self.assertEqual(vasprun_skip.nionic_steps, vasprun.nionic_steps) self.assertNotAlmostEqual(vasprun_skip.final_energy, vasprun.final_energy) # Test with ionic_step_offset vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False) self.assertEqual(len(vasprun_offset.ionic_steps), int(len(vasprun.ionic_steps) / 3) - 1) self.assertEqual(vasprun_offset.structures[0], vasprun_skip.structures[2]) self.assertTrue(vasprun_ggau.is_hubbard) self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3) self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[(Spin.up, 0, 0, 96, Orbital.s)], 0.0032) d = vasprun_ggau.as_dict() self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"]) self.assertEqual(d["nelements"], 4) filepath = os.path.join(test_dir, 'vasprun.xml.unconverged') with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False) # Verify some things self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, UnconvergedVASPWarning)) self.assertTrue(vasprun_unconverged.converged_ionic) self.assertFalse(vasprun_unconverged.converged_electronic) self.assertFalse(vasprun_unconverged.converged) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt') vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357) self.assertTrue(vasprun_dfpt.converged) entry = vasprun_dfpt.get_computed_entry() entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry) self.assertAlmostEqual(entry.uncorrected_energy + entry.correction, entry.energy) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic') vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged') vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False) self.assertFalse(vasprun_dfpt_unconv.converged_electronic) self.assertTrue(vasprun_dfpt_unconv.converged_ionic) self.assertFalse(vasprun_dfpt_unconv.converged) vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"), parse_potcar_file=False) self.assertEqual(vasprun_uniform.kpoints.style, Kpoints.supported_modes.Reciprocal) vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"), parse_potcar_file=False) self.assertIsNotNone(vasprun_no_pdos.complete_dos) self.assertFalse(vasprun_no_pdos.dos_has_errors) vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"), parse_potcar_file=False) self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3]) v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz")) (gap, cbm, vbm, direct) = v.eigenvalue_band_properties self.assertFalse(direct)
def test_properties(self): filepath = os.path.join(test_dir, 'vasprun.xml.nonlm') vasprun = Vasprun(filepath, parse_potcar_file=False) orbs = list(vasprun.complete_dos.pdos[vasprun.final_structure[ 0]].keys()) self.assertIn(OrbitalType.s, orbs) filepath = os.path.join(test_dir, 'vasprun.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) #Test NELM parsing. self.assertEqual(vasprun.parameters["NELM"], 60) #test pdos parsing pdos0 = vasprun.complete_dos.pdos[vasprun.final_structure[0]] self.assertAlmostEqual(pdos0[Orbital.s][Spin.up][16], 0.0026) self.assertAlmostEqual(pdos0[Orbital.pz][Spin.down][16], 0.0012) self.assertEqual(pdos0[Orbital.s][Spin.up].shape, (301, )) filepath2 = os.path.join(test_dir, 'lifepo4.xml') vasprun_ggau = Vasprun(filepath2, parse_projected_eigen=True, parse_potcar_file=False) totalscsteps = sum([len(i['electronic_steps']) for i in vasprun.ionic_steps]) self.assertEqual(29, len(vasprun.ionic_steps)) self.assertEqual(len(vasprun.structures), len(vasprun.ionic_steps)) self.assertEqual(vasprun.lattice, vasprun.lattice_rec.reciprocal_lattice) for i, step in enumerate(vasprun.ionic_steps): self.assertEqual(vasprun.structures[i], step["structure"]) self.assertTrue(all([vasprun.structures[i] == vasprun.ionic_steps[i][ "structure"] for i in range(len(vasprun.ionic_steps))])) self.assertEqual(308, totalscsteps, "Incorrect number of energies read from vasprun.xml") self.assertEqual(['Li'] + 4 * ['Fe'] + 4 * ['P'] + 16 * ["O"], vasprun.atomic_symbols) self.assertEqual(vasprun.final_structure.composition.reduced_formula, "LiFe4(PO4)4") self.assertIsNotNone(vasprun.incar, "Incar cannot be read") self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.eigenvalues, "Eigenvalues cannot be read") self.assertAlmostEqual(vasprun.final_energy, -269.38319884, 7) self.assertAlmostEqual(vasprun.tdos.get_gap(), 2.0589, 4) expectedans = (2.539, 4.0906, 1.5516, False) (gap, cbm, vbm, direct) = vasprun.eigenvalue_band_properties self.assertAlmostEqual(gap, expectedans[0]) self.assertAlmostEqual(cbm, expectedans[1]) self.assertAlmostEqual(vbm, expectedans[2]) self.assertEqual(direct, expectedans[3]) self.assertFalse(vasprun.is_hubbard) self.assertEqual(vasprun.potcar_symbols, ['PAW_PBE Li 17Jan2003', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE Fe 06Sep2000', 'PAW_PBE P 17Jan2003', 'PAW_PBE O 08Apr2002']) self.assertIsNotNone(vasprun.kpoints, "Kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints, "Actual kpoints cannot be read") self.assertIsNotNone(vasprun.actual_kpoints_weights, "Actual kpoints weights cannot be read") for atomdoses in vasprun.pdos: for orbitaldos in atomdoses: self.assertIsNotNone(orbitaldos, "Partial Dos cannot be read") # test skipping ionic steps. vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False) self.assertEqual(vasprun_skip.nionic_steps, 29) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) self.assertEqual(len(vasprun_skip.ionic_steps), len(vasprun_skip.structures)) self.assertEqual(len(vasprun_skip.ionic_steps), int(vasprun.nionic_steps / 3) + 1) # Check that nionic_steps is preserved no matter what. self.assertEqual(vasprun_skip.nionic_steps, vasprun.nionic_steps) self.assertNotAlmostEqual(vasprun_skip.final_energy, vasprun.final_energy) # Test with ionic_step_offset vasprun_offset = Vasprun(filepath, 3, 6, parse_potcar_file=False) self.assertEqual(len(vasprun_offset.ionic_steps), int(len(vasprun.ionic_steps) / 3) - 1) self.assertEqual(vasprun_offset.structures[0], vasprun_skip.structures[2]) self.assertTrue(vasprun_ggau.is_hubbard) self.assertEqual(vasprun_ggau.hubbards["Fe"], 4.3) self.assertAlmostEqual(vasprun_ggau.projected_eigenvalues[Spin.up][ 0][0][96][0], 0.0032) d = vasprun_ggau.as_dict() self.assertEqual(d["elements"], ["Fe", "Li", "O", "P"]) self.assertEqual(d["nelements"], 4) filepath = os.path.join(test_dir, 'vasprun.xml.unconverged') with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. vasprun_unconverged = Vasprun(filepath, parse_potcar_file=False) # Verify some things self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, UnconvergedVASPWarning)) self.assertTrue(vasprun_unconverged.converged_ionic) self.assertFalse(vasprun_unconverged.converged_electronic) self.assertFalse(vasprun_unconverged.converged) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt') vasprun_dfpt = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][0], 3.26105533) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[0][1], -0.00459066) self.assertAlmostEqual(vasprun_dfpt.epsilon_static[2][2], 3.24330517) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][0], 3.33402531) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[0][1], -0.00559998) self.assertAlmostEqual(vasprun_dfpt.epsilon_static_wolfe[2][2], 3.31237357) self.assertTrue(vasprun_dfpt.converged) entry = vasprun_dfpt.get_computed_entry() entry = MaterialsProjectCompatibility(check_potcar_hash=False).process_entry(entry) self.assertAlmostEqual(entry.uncorrected_energy + entry.correction, entry.energy) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.ionic') vasprun_dfpt_ionic = Vasprun(filepath, parse_potcar_file=False) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][0], 515.73485838) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[0][1], -0.00263523) self.assertAlmostEqual(vasprun_dfpt_ionic.epsilon_ionic[2][2], 19.02110169) filepath = os.path.join(test_dir, 'vasprun.xml.dfpt.unconverged') vasprun_dfpt_unconv = Vasprun(filepath, parse_potcar_file=False) self.assertFalse(vasprun_dfpt_unconv.converged_electronic) self.assertTrue(vasprun_dfpt_unconv.converged_ionic) self.assertFalse(vasprun_dfpt_unconv.converged) vasprun_uniform = Vasprun(os.path.join(test_dir, "vasprun.xml.uniform"), parse_potcar_file=False) self.assertEqual(vasprun_uniform.kpoints.style, Kpoints.supported_modes.Reciprocal) vasprun_no_pdos = Vasprun(os.path.join(test_dir, "Li_no_projected.xml"), parse_potcar_file=False) self.assertIsNotNone(vasprun_no_pdos.complete_dos) self.assertFalse(vasprun_no_pdos.dos_has_errors) vasprun_diel = Vasprun(os.path.join(test_dir, "vasprun.xml.dielectric"), parse_potcar_file=False) self.assertAlmostEqual(0.4294,vasprun_diel.dielectric[0][10]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][0]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][1]) self.assertAlmostEqual(19.941,vasprun_diel.dielectric[1][51][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[1][51][3]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][0]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][1]) self.assertAlmostEqual(34.186,vasprun_diel.dielectric[2][85][2]) self.assertAlmostEqual(0.0,vasprun_diel.dielectric[2][85][3]) v = Vasprun(os.path.join(test_dir, "vasprun.xml.indirect.gz")) (gap, cbm, vbm, direct) = v.eigenvalue_band_properties self.assertFalse(direct)
def read_phase_diagram_and_chempots(self, full_sub_approach=False, include_mp_entries=True): """ Once phase diagram has been set up and run by user (in a folder called "PhaseDiagram"), this method parses and prints the chemical potentials based on the computed entries. The methodology is basically identical to that in the analyze_GGA_chempots method. Will supplement unfinished entries with MP database entries unless no_mp_entries is set to False Args: full_sub_approach: same attribute as described at length in the analyze_GGA_chempots method. Basically, the user can set this to True if they want to mix extrinsic species in the phase diagram include_mp_entries: if set to True, extra entries from Materials Project will be added to phase diagram according to phases that are stable in the Materials Project database """ pdfile = os.path.join(self.path_base, 'PhaseDiagram') if not os.path.exists(pdfile): print('Phase diagram file does not exist at ', pdfile) return # this is where we read computed entries into a list for parsing... # NOTE TO USER: If not running with VASP need to use another # pymatgen functionality for importing computed entries below... personal_entry_list = [] for structfile in os.listdir(pdfile): if os.path.exists(os.path.join(pdfile, structfile, 'vasprun.xml')): try: print('loading ', structfile) vr = Vasprun(os.path.join(pdfile, structfile, 'vasprun.xml'), parse_potcar_file=False) personal_entry_list.append(vr.get_computed_entry()) except: print('Could not load ', structfile) #add bulk computed entry to phase diagram, and see if it is stable if not self.bulk_ce: vr_path = os.path.join(self.path_base, 'bulk', 'vasprun.xml') if os.path.exists(vr_path): print('loading bulk computed entry') bulkvr = Vasprun(vr_path) self.bulk_ce = bulkvr.get_computed_entry() else: print ('No bulk entry given locally. Phase diagram ' + \ 'calculations cannot be set up without this') return self.bulk_composition = self.bulk_ce.composition self.redcomp = self.bulk_composition.reduced_composition # Supplement entries to phase diagram with those from MP database if include_mp_entries: mpcpa = MPChemPotAnalyzer(bulk_ce=self.bulk_ce, sub_species=self.sub_species, mapi_key=self.mapi_key) tempcl = mpcpa.analyze_GGA_chempots( full_sub_approach=full_sub_approach) # Use MPentries curr_pd = PhaseDiagram( list(set().union(mpcpa.entries['bulk_derived'], mpcpa.entries['subs_set']))) stable_idlist = { i.composition.reduced_composition: [i.energy_per_atom, i.entry_id, i] for i in curr_pd.stable_entries } for mpcomp, mplist in stable_idlist.items(): matched = False for pe in personal_entry_list: if (pe.composition.reduced_composition == mpcomp): # #USER: uncomment this if you want additional stable phases of identical composition included in your phase diagram # if personalentry.energy_per_atom > mplist[0]: # print('Adding entry from MP-database:',mpcomp,'(entry-id:',mplist[1]) # personal_entry_list.append(mplist[2]) matched = True if not matched: print('Adding entry from MP-database:', mpcomp, '(entry-id:', mplist[1]) personal_entry_list.append(mplist[2]) else: personal_entry_list.append(self.bulk_ce) #if you dont have entries for elemental corners of phase diagram then code breaks #manually inserting entries with energies of zero for competeness...USER DO NOT USE THIS eltcount = { elt: 0 for elt in set(self.bulk_ce.composition.elements) } for pentry in personal_entry_list: if pentry.is_element: eltcount[pentry.composition.elements[0]] += 1 for elt, eltnum in eltcount.items(): if not eltnum: s = Structure([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]], [elt], [[0, 0, 0]]) eltentry = ComputedStructureEntry(s, 0.) print( 'USER! Note that you have added a fake ' + str(elt) + ' structure to prevent from breaking the ' 'Phase Diagram Analyzer.\n As a result DO NOT trust the chemical potential results for regions ' 'of phase diagram that involve the element ' + str(elt)) personal_entry_list.append(eltentry) personal_entry_list.append(self.bulk_ce) #compute chemical potentials if full_sub_approach: pd = PhaseDiagram(personal_entry_list) chem_lims = self.get_chempots_from_pd(pd) else: #first seperate out the bulk associated elements from those of substitutional elements entry_list = [] sub_associated_entry_list = [] for localentry in personal_entry_list: bulk_associated = True for elt in localentry.composition.elements: if elt not in self.bulk_composition.elements: bulk_associated = False if bulk_associated: entry_list.append(localentry) else: sub_associated_entry_list(localentry) #now iterate through and collect chemical potentials pd = PhaseDiagram(entry_list) chem_lims = self.get_chempots_from_pd(pd) finchem_lims = {} # this will be final chem_lims dictionary for key in chem_lims.keys(): face_list = key.split('-') blk, blknom, subnom = self.diff_bulk_sub_phases(face_list) finchem_lims[blknom] = {} finchem_lims[blknom] = chem_lims[key] # Now consider adding single elements to extend the phase diagram, # adding new additions to chemical potentials ONLY for the cases # where the phases in equilibria are those from the bulk phase # diagram. This is essentially the assumption that the majority of # the elements in the total composition will be from the native # species present rather than the sub species (a good approximation) for sub_el in self.sub_species: sub_specie_entries = entry_list[:] for entry in sub_associated_entry_list: if sub_el in entry.composition.elements: sub_specie_entries.append(entry) pd = PhaseDiagram(sub_specie_entries) chem_lims = self.get_chempots_from_pd(pd) for key in chem_lims.keys(): face_list = key.split('-') blk, blknom, subnom = self.diff_bulk_sub_phases( face_list, sub_el=sub_el) # if one less than number of bulk species then can be # grouped with rest of structures if len(blk) == len(self.bulk_species_symbol): if blknom not in finchem_lims.keys(): finchem_lims[blknom] = chem_lims[key] else: finchem_lims[blknom][sub_el] = \ chem_lims[key][sub_el] if 'name-append' not in finchem_lims[blknom].keys(): finchem_lims[blknom]['name-append'] = subnom else: finchem_lims[blknom]['name-append'] += '-' + subnom else: # if chem pots determined by two (or more) sub-specie # containing phases, skip this facet! continue # run a check to make sure all facets dominantly defined by bulk species overdependent_chempot = False facets_to_delete = [] for facet_name, cps in finchem_lims.items(): cp_key_num = (len(cps.keys()) - 1) if 'name-append' in cps else len(cps.keys()) bulk_species_symbol = [ s.symbol for s in self.bulk_composition.elements ] if cp_key_num != (len(bulk_species_symbol) + len(self.sub_species)): facets_to_delete.append(facet_name) print( "Not using facet {} because insufficient number of bulk facets for " "bulk set {} with sub_species set {}. (only dependent on {})." "".format(facet_name, self.bulk_species_symbol, self.sub_species, cps.get('name-append'))) if len(facets_to_delete) == len(finchem_lims): overdependent_chempot = True print( "Determined chemical potentials to be over dependent" " on a substitutional specie. Needing to revert to full_sub_approach. If " "multiple sub species exist this could take a while/break the code..." ) else: finchem_lims = { k: v for k, v in finchem_lims.items() if k not in facets_to_delete } if not overdependent_chempot: chem_lims = {} for orig_facet, fc_cp_dict in finchem_lims.items(): if 'name-append' not in fc_cp_dict: facet_nom = orig_facet else: full_facet_list = orig_facet.split('-') full_facet_list.extend( fc_cp_dict['name-append'].split('-')) full_facet_list.sort() facet_nom = '-'.join(full_facet_list) chem_lims[facet_nom] = { k: v for k, v in fc_cp_dict.items() if k != 'name-append' } else: # This is for when overdetermined chempots occur, forcing the full_sub_approach to happen for sub, subentries in self.entries['subs_set'].items(): for subentry in subentries: entry_list.append(subentry) pd = PhaseDiagram(entry_list) chem_lims = self.get_chempots_from_pd(pd) return chem_lims
class VasprunAnalysis(): """ can perform all custermized analysis of a single vasprun.xml file Includes: phase diagram analysis, energy above hull, formation energy..... Band gap.... will add more functionality in the future """ def __init__(self, vasprun_file, cal_pd=False): self.vasprun = Vasprun(vasprun_file) if cal_pd: self.pd, self.entry = self.get_pd() 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_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 get_formation_energy(self): """ get formation energy per atom for this compound Returns: formation energy per atom """ return self.pd.get_form_energy_per_atom(self.entry) 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_eg(self): """ return the band gap(by me), band gap(by pymatgen) and direct band gap two ways of calculating band gap to test the correctness of pymatgen algorithm Returns: eg1: band gap calculated by me eg2: band gap calculated by pymatgen algorithm eg_direct: direct band gap """ eg1 = self.vasprun.eigenvalue_band_properties[0] efermi = self.vasprun.efermi vbm = self.vasprun.eigenvalue_band_properties[2] eig = [self.vasprun.eigenvalues[i] for i in self.vasprun.eigenvalues] occu = [i.tolist() for i in eig] occu_flat = [ i[1] for sublist in occu for subsublist in sublist for i in subsublist ] occu_set = set(occu_flat) if efermi < vbm: eg1 = 0 elif len(occu_set) > 2: eg1 = 0 bs = self.vasprun.get_band_structure() eg2 = bs.get_band_gap()['energy'] eg_direct = bs.get_direct_band_gap() print('eg1 = {}, eg2 = {}, eg_direct = {}'.format(eg1, eg2, eg_direct)) print('check if eg1 = eg2, it should') print('transition: {}'.format(bs.get_band_gap()['transition'])) return eg1, eg2, eg_direct
#for same composition from pymatgen.io.vasp.outputs import Vasprun from pymatgen.entries.computed_entries import ComputedEntry import os entries = [] rootdir = os.getcwd() directory_contents = os.listdir(rootdir) for dir in directory_contents: if os.path.isdir(dir): os.chdir(dir) if os.path.isfile("vasprun.xml"): print("File exist") vrun = Vasprun("vasprun.xml") entry_temp = vrun.get_computed_entry() entry_temp.entry_id = dir entries.append(entry_temp) os.chdir("../") entries_sorted = sorted(entries, key=lambda entry: entry.energy_per_atom) # sort by age from pymatgen.io.vasp.outputs import Vasprun from pymatgen.entries.compatibility import MaterialsProjectCompatibility import os import glob from os import path import copy import json all = []
def assimilate(self, path): files = os.listdir(path) ciffilepath = None if any("relax1" in s for s in files) and any("relax2" in s for s in files): filepath = glob.glob(os.path.join(path, "vasprun.xml.relax2*"))[0] try: incarfilepath = glob.glob(os.path.join(path,'INCAR.relax1*'))[0] except: print path #Get cif from directory # if glob.glob(os.path.join(path,'*cif')): # ciffilepath = glob.glob(os.path.join(path,'*cif'))[0] contcarfile = glob.glob(os.path.join(path,"CONTCAR.relax2*"))[0] else: vasprun_files = glob.glob(os.path.join(path, "vasprun.xml*")) try: incarfilepath = glob.glob(os.path.join(path,"INCAR*"))[0] except: print path #Get cif from directory # if glob.glob(os.path.join(path,'*cif')): # ciffilepath = glob.glob(os.path.join(path,'*cif'))[0] contcarfile = glob.glob(os.path.join(path,"CONTCAR*"))[0] filepath = None if len(vasprun_files) == 1: filepath = vasprun_files[0] logging.debug(filepath) elif len(vasprun_files) > 1: """ This is a bit confusing, since there maybe be multi-steps. By default, assimilate will try to find a file simply named vasprun.xml, vasprun.xml.bz2, or vasprun.xml.gz. Failing which it will try to get a relax2 from an aflow style run if possible. Or else, a randomly chosen file containing vasprun.xml is chosen. """ for fname in vasprun_files: if os.path.basename(fname) in ["vasprun.xml", "vasprun.xml.gz", "vasprun.xml.bz2"]: filepath = fname break if re.search("relax2", fname): filepath = fname break filepath = fname try: vasprun = Vasprun(filepath) except Exception as ex: logger.debug("error in {}: {}".format(filepath, ex)) return None logging.debug('Done entry if') entry = vasprun.get_computed_entry(self._inc_structure, parameters=self._parameters, data=self._data) logging.debug(entry) entry.parameters["history"] = _get_transformation_history(path) incar = Incar.from_file(incarfilepath) try: entry.data['NUPDOWN'] = incar['NUPDOWN'] entry.data['ISMEAR'] = incar['ISMEAR'] except: pass logging.debug('Return Entry step') entry.data['CONTCAR_Structure'] = Structure.from_file(contcarfile,primitive=False) # if ciffilepath: # entry.data['Cif_Structure'] = Structure.from_file(ciffilepath,primitive=False) return entry