def get_band_edges(): """ Calculate the band edge locations relative to the vacuum level for a semiconductor. If spin-polarized, returns all 4 band edges. """ # Vacuum level energy from LOCPOT. locpot = Locpot.from_file("LOCPOT") evac = max(locpot.get_average_along_axis(2)) vasprun = Vasprun("vasprun.xml") efermi = vasprun.efermi - evac if vasprun.get_band_structure().is_spin_polarized: eigenvals = {Spin.up: [], Spin.down: []} for band in vasprun.eigenvalues: for eigenvalue in vasprun.eigenvalues[band]: eigenvals[band[0]].append(eigenvalue) up_cbm = min([e[0] for e in eigenvals[Spin.up] if not e[1]]) - evac up_vbm = max([e[0] for e in eigenvals[Spin.up] if e[1]]) - evac dn_cbm = min([e[0] for e in eigenvals[Spin.down] if not e[1]]) - evac dn_vbm = max([e[0] for e in eigenvals[Spin.down] if e[1]]) - evac edges = {"up_cbm": up_cbm, "up_vbm": up_vbm, "dn_cbm": dn_cbm, "dn_vbm": dn_vbm, "efermi": efermi} else: bs = vasprun.get_band_structure() cbm = bs.get_cbm()["energy"] - evac vbm = bs.get_vbm()["energy"] - evac edges = {"cbm": cbm, "vbm": vbm, "efermi": efermi} return edges
def find_dirac_nodes(): """ Look for band crossings near (within `tol` eV) the Fermi level. Returns: boolean. Whether or not a band crossing occurs at or near the fermi level. """ vasprun = Vasprun('vasprun.xml') dirac = False if vasprun.get_band_structure().get_band_gap()['energy'] < 0.1: efermi = vasprun.efermi bsp = BSPlotter(vasprun.get_band_structure('KPOINTS', line_mode=True, efermi=efermi)) bands = [] data = bsp.bs_plot_data(zero_to_efermi=True) for d in range(len(data['distances'])): for i in range(bsp._nb_bands): x = data['distances'][d], y = [data['energy'][d][str(Spin.up)][i][j] for j in range(len(data['distances'][d]))] band = [x, y] bands.append(band) considered = [] for i in range(len(bands)): for j in range(len(bands)): if i != j and (j, i) not in considered: considered.append((j, i)) for k in range(len(bands[i][0])): if ((-0.1 < bands[i][1][k] < 0.1) and (-0.1 < bands[i][1][k] - bands[j][1][k] < 0.1)): dirac = True return dirac
def test_get_band_structure(self): filepath = os.path.join(test_dir, 'vasprun_Si_bands.xml') vasprun = Vasprun(filepath, parse_projected_eigen=True, parse_potcar_file=False) bs = vasprun.get_band_structure(kpoints_filename= os.path.join(test_dir, 'KPOINTS_Si_bands')) cbm = bs.get_cbm() vbm = bs.get_vbm() self.assertEqual(cbm['kpoint_index'], [13], "wrong cbm kpoint index") self.assertAlmostEqual(cbm['energy'], 6.2301, "wrong cbm energy") self.assertEqual(cbm['band_index'], {Spin.up: [4], Spin.down: [4]}, "wrong cbm bands") self.assertEqual(vbm['kpoint_index'], [0, 63, 64]) self.assertAlmostEqual(vbm['energy'], 5.6158, "wrong vbm energy") self.assertEqual(vbm['band_index'], {Spin.up: [1, 2, 3], Spin.down: [1, 2, 3]}, "wrong vbm bands") self.assertEqual(vbm['kpoint'].label, "\Gamma", "wrong vbm label") self.assertEqual(cbm['kpoint'].label, None, "wrong cbm label") projected = bs.get_projection_on_elements() self.assertAlmostEqual(projected[Spin.up][0][0]["Si"], 0.4238) projected = bs.get_projections_on_elements_and_orbitals({"Si": ["s"]}) self.assertAlmostEqual(projected[Spin.up][0][0]["Si"]["s"], 0.4238)
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 plot_orb_projected_bands(orbitals, fmt='pdf', ylim=(-5, 5)): """ Plot a separate band structure for each orbital of each element in orbitals. Args: orbitals (dict): dictionary of the form {element: [orbitals]}, e.g. {'Mo': ['s', 'p', 'd'], 'S': ['p']} ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun('vasprun.xml', parse_projected_eigen=True) bs = vasprun.get_band_structure('KPOINTS', line_mode=True) bspp = BSPlotterProjected(bs) ax = bspp.get_projected_plots_dots(orbitals, ylim=ylim).gcf().gca() ax.set_xticklabels([r'$\mathrm{%s}$' % t for t in ax.get_xticklabels()]) ax.set_yticklabels([r'$\mathrm{%s}$' % t for t in ax.get_yticklabels()]) if fmt == "None": return ax else: plt.savefig('orb_projected_bands.{}'.format(fmt)) plt.close()
def plot_local_potential(axis=2, ylim=(-20, 0), fmt='pdf'): """ Plot data from the LOCPOT file along any of the 3 primary axes. Useful for determining surface dipole moments and electric potentials on the interior of the material. Args: axis (int): 0 = x, 1 = y, 2 = z ylim (tuple): minimum and maximum potentials for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ ax = plt.figure(figsize=(16, 10)).gca() locpot = Locpot.from_file('LOCPOT') structure = Structure.from_file('CONTCAR') vd = VolumetricData(structure, locpot.data) abs_potentials = vd.get_average_along_axis(axis) vacuum_level = max(abs_potentials) vasprun = Vasprun('vasprun.xml') bs = vasprun.get_band_structure() if not bs.is_metal(): cbm = bs.get_cbm()['energy'] - vacuum_level vbm = bs.get_vbm()['energy'] - vacuum_level potentials = [potential - vacuum_level for potential in abs_potentials] axis_length = structure.lattice._lengths[axis] positions = np.arange(0, axis_length, axis_length / len(potentials)) ax.plot(positions, potentials, linewidth=2, color='k') ax.set_xlim(0, axis_length) ax.set_ylim(ylim[0], ylim[1]) ax.set_xticklabels( [r'$\mathrm{%s}$' % tick for tick in ax.get_xticks()], size=20) ax.set_yticklabels( [r'$\mathrm{%s}$' % tick for tick in ax.get_yticks()], size=20) ax.set_xlabel(r'$\mathrm{\AA}$', size=24) ax.set_ylabel(r'$\mathrm{V\/(eV)}$', size=24) if not bs.is_metal(): ax.text(ax.get_xlim()[1], cbm, r'$\mathrm{CBM}$', horizontalalignment='right', verticalalignment='bottom', size=20) ax.text(ax.get_xlim()[1], vbm, r'$\mathrm{VBM}$', horizontalalignment='right', verticalalignment='top', size=20) ax.fill_between(ax.get_xlim(), cbm, ax.get_ylim()[1], facecolor=plt.cm.jet(0.3), zorder=0, linewidth=0) ax.fill_between(ax.get_xlim(), ax.get_ylim()[0], vbm, facecolor=plt.cm.jet(0.7), zorder=0, linewidth=0) if fmt == "None": return ax else: plt.savefig('locpot.{}'.format(fmt)) plt.close()
def test_as_dict(self): filepath = os.path.join(test_dir, "vasprun.xml") vasprun = Vasprun(filepath, parse_potcar_file=False) # Test that as_dict() is json-serializable self.assertIsNotNone(json.dumps(vasprun.as_dict())) self.assertEqual( vasprun.as_dict()["input"]["potcar_type"], ["PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE", "PAW_PBE"] )
def __init__(self, filename, ionic_step_skip=None, ionic_step_offset=0, parse_dos=True, parse_eigen=True, parse_projected_eigen=False, parse_potcar_file=True): Vasprun.__init__(self, filename, ionic_step_skip=ionic_step_skip, ionic_step_offset=ionic_step_offset, parse_dos=parse_dos, parse_eigen=parse_eigen, parse_projected_eigen=parse_projected_eigen, parse_potcar_file=parse_potcar_file)
def test_get_band_structure(self): filepath = os.path.join(test_dir, "vasprun_Si_bands.xml") vasprun = Vasprun(filepath, parse_potcar_file=False) bs = vasprun.get_band_structure(kpoints_filename=os.path.join(test_dir, "KPOINTS_Si_bands")) cbm = bs.get_cbm() vbm = bs.get_vbm() self.assertEqual(cbm["kpoint_index"], [13], "wrong cbm kpoint index") self.assertAlmostEqual(cbm["energy"], 6.2301, "wrong cbm energy") self.assertEqual(cbm["band_index"], {Spin.up: [4], Spin.down: [4]}, "wrong cbm bands") self.assertEqual(vbm["kpoint_index"], [0, 63, 64]) self.assertAlmostEqual(vbm["energy"], 5.6158, "wrong vbm energy") self.assertEqual(vbm["band_index"], {Spin.up: [1, 2, 3], Spin.down: [1, 2, 3]}, "wrong vbm bands") self.assertEqual(vbm["kpoint"].label, "\Gamma", "wrong vbm label") self.assertEqual(cbm["kpoint"].label, None, "wrong cbm label")
def get_stdrd_metadata(self): if not self.bulk_vr: path_to_bulk = self.defect_entry.parameters["bulk_path"] self.bulk_vr = Vasprun( os.path.join(path_to_bulk, "vasprun.xml")) if not self.defect_vr: path_to_defect = self.defect_entry.parameters["defect_path"] self.defect_vr = Vasprun( os.path.join(path_to_defect, "vasprun.xml")) # standard bulk metadata bulk_energy = self.bulk_vr.final_energy bulk_sc_structure = self.bulk_vr.initial_structure self.defect_entry.parameters.update( {"bulk_energy": bulk_energy, "bulk_sc_structure": bulk_sc_structure}) # standard run metadata run_metadata = {} run_metadata.update( {"defect_incar": self.defect_vr.incar, "bulk_incar": self.bulk_vr.incar, "defect_kpoints": self.defect_vr.kpoints, "bulk_kpoints": self.bulk_vr.kpoints}) run_metadata.update( {"incar_calctype_summary": {k: self.defect_vr.incar.get(k, None) \ if self.defect_vr.incar.get(k) not in ["None", "False", False] else None \ for k in ["LHFCALC", "HFSCREEN", "IVDW", "LUSE_VDW", "LDAU", "METAGGA"] } } ) run_metadata.update({"potcar_summary": {"pot_spec": [potelt["titel"] for potelt in self.defect_vr.potcar_spec], "pot_labels": self.defect_vr.potcar_spec, "pot_type": self.defect_vr.run_type} }) self.defect_entry.parameters.update( {"run_metadata": run_metadata.copy()}) # standard defect run metadata self.defect_entry.parameters.update({"final_defect_structure": self.defect_vr.final_structure, "initial_defect_structure": self.defect_vr.initial_structure, "defect_energy": self.defect_vr.final_energy}) # grab defect energy and eigenvalue information for band filling and localization analysis eigenvalues = {spincls.value: eigdict.copy() for spincls, eigdict in self.defect_vr.eigenvalues.items()} kpoint_weights = self.defect_vr.actual_kpoints_weights[:] self.defect_entry.parameters.update({"eigenvalues": eigenvalues, "kpoint_weights": kpoint_weights}) return
def dos_graph_soc(rawdatadir, savedir): dosrun = Vasprun("{}/vasprun.xml".format(rawdatadir), soc=True, parse_dos=True) dos = dosrun.complete_dos orbitals = { "s": Orbital.s, "p_y": Orbital.py, "p_z": Orbital.pz, "p_x": Orbital.px, "d_xy": Orbital.dxy, "d_yz": Orbital.dyz, "d_z2-r2": Orbital.dz2, "d_xz": Orbital.dxz, "d_x2-y2": Orbital.dx2 } spinor_component = { "mtot": SpinNonCollinear.mtot, "mx": SpinNonCollinear.mx, "my": SpinNonCollinear.my, "mz": SpinNonCollinear.mz } for m in spinor_component: dosplot = DosPlotter() if m == "mtot": dosplot.add_dos("Total DOS with SOC", dos.tdos) dosplot.add_dos_dict(dos.get_element_dos()) plt = dosplot.get_plot(xlim=[-3, 3], soc=True, spinor_component=spinor_component[m], element_colors=True) plt.grid() plt.savefig("{}/DOSGraph_{}_{}".format(savedir, m, "DOS by Element with SOC")) plt.close() for m in spinor_component: dosplot = DosPlotter() if m == "mtot": dosplot.add_dos("Total DOS with SOC", dos.tdos) dosplot.add_dos_dict(dos.get_orbital_dos()) plt = dosplot.get_plot(xlim=[-3, 3], soc=True, spinor_component=spinor_component[m]) plt.grid() plt.savefig("{}/DOSGraph_{}_{}".format(savedir, m, "DOS by Orbital with SOC")) plt.close() # Get detailed info about band gap (source: vasprun.xml) dos_graph_soc.e_fermi = float(dosrun.efermi) dos_graph_soc.electronic_gap = \ dosrun.tdos.get_gap_alt(xlim=[-3,3],e_fermi=dos_graph_soc.e_fermi, tol=0.001,abs_tol=False, spin=SpinNonCollinear.mtot) return
def vasp_run_main(pwd): # called in driver completed_jobs = {'PATHs': {}} computed_entries = [] for root, dirs, files in os.walk(pwd): for file in files: if file == 'POTCAR': if check_vasp_input(root) == True: print('#********************************************#\n') job_name = get_job_name(root) if not_in_queue(root) == True: if check_path_exists(os.path.join(root, 'vasprun.xml')): try: V = Vasprun(os.path.join(root, 'vasprun.xml')) fizzled = False except: print(root, ' Fizzled job, check errors! Attempting to resubmit...') fizzled = True if fizzled == False: os.chdir(root) job = is_converged(root) rerun_job(job, job_name) if job == 'converged': completed_jobs['PATHs'][str(root)] = str(job_name) store_dict = store_data(V, job_name) computed_entries.append(store_dict) else: pass else: os.chdir(root) job = fizzled_job(root) rerun_job(job, job_name) elif check_path_exists(os.path.join(root, 'CONVERGENCE')): print(job_name + ' Initializing multi-step run.') os.chdir(root) rerun_job('multi_initial', job_name) else: print(job_name + ' Initializing run.') os.chdir(root) rerun_job('single', job_name) else: print(job_name + ' Job in queue. Status: ' + not_in_queue(root)) print('\n') num_jobs_in_workflow = check_num_jobs_in_workflow(pwd) if num_jobs_in_workflow > 1: if not completed_jobs: pass else: with open(os.path.join(pwd, 'completed_jobs.yml'), 'w') as outfile: yaml.dump(completed_jobs, outfile, default_flow_style=False) if len(list(completed_jobs['PATHs'].keys())) == num_jobs_in_workflow: print('\n ALL JOBS HAVE CONVERGED! \n') with open(os.path.join(pwd, 'WORKFLOW_CONVERGENCE'), 'w') as f: f.write('WORKFLOW_CONVERGED = True') f.close() return computed_entries
def severalFromFile(sim_args): structs = [] names = [] energies = [] for key in sim_args["struct_sets"].keys(): if sim_args["struct_sets"][key]["set_type"] == "POSCAR_dir": # Iterate through the directory, grabbing the structure from every file for filename in listdir(sim_args["struct_sets"][key]["set_file"]): structs.append(Poscar.from_file("{}/{}".format(sim_args["struct_sets"][key]["set_file"],filename)).structure) names.append(key) energies.append(None) elif sim_args["struct_sets"][key]["set_type"] == "enum": # Copy the enum.in file to a temporary directory enum_dir = TemporaryDirectory() system("cp {} {}".format(sim_args["struct_sets"][key]["set_file"], enum_dir.name)) # Move to the temporary directory and run enum.x current = getcwd() chdir(enum_dir.name) system("enum.x {}".format(sim_args["struct_sets"][key]["set_file"][9:])) # Grab all the structures for makeStr.py id_mapping = {v: k for k, v in sim_args["atom_mapping"].items()} args = { "id_mapping":id_mapping, "mink":True, "scale_factor":1.0, "remove_zeros":True, "vegards":False, "vacancy": sim_args["vacancy"] if "vacancy" in sim_args.keys() else None, "rattle":0.0, "displace":0.0 } new_structs = makeStructures(args) chdir(current) new_names = [key] * len(new_structs) # Add the structures and names to the rest structs += new_structs names += new_names energies += [None] * len(new_names) elif sim_args["struct_sets"][key]["set_type"] == "vasprun": simplefilter('error',UnconvergedVASPWarning) for filename in listdir(sim_args["struct_sets"][key]["set_file"]): try: vasprun = Vasprun("{}/{}".format(sim_args["struct_sets"][key]["set_file"],filename), parse_potcar_file=False).ionic_steps[-1] except FileNotFoundError: continue except ParseError: continue except UnconvergedVASPWarning: continue structs.append(vasprun["structure"]) names.append(key) energies.append(vasprun["e_fr_energy"]) simplefilter('default',UnconvergedVASPWarning) return structs, names, energies
def vr(filepaths): offset = 0 for p in filepaths: v = Vasprun(p, ionic_step_offset=offset, ionic_step_skip=step_skip) yield v # Recompute offset. offset = (-(v.nionic_steps - offset)) % step_skip
def test_sc_step_overflow(self): filepath = os.path.join(test_dir, 'vasprun.xml.sc_overflow') with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") vasprun = Vasprun(filepath) self.assertEqual(len(w), 3) estep = vasprun.ionic_steps[0]['electronic_steps'][29] self.assertTrue(np.isnan(estep['e_wo_entrp']))
def _get_vasprun(args): """ Internal method to support multiprocessing. """ return Vasprun(args[0], ionic_step_skip=args[1], parse_dos=False, parse_eigen=False)
def read_results(self, results_list=[ "struct_name", "initial_energy", "total_energy", "initial_forces", "final_forces" ]): """ Reads results from calculated files, vasprun.xml. Arguments --------- vasprun: pymatgen.io.vasp.outputs.Vasprun vasprun.xml file, which includes all calculation results. results_list List of required results. Returns ------- results: dict dictionary of caluclation results. """ results = {} try: if self._output_path is not None: vasprun = Vasprun(self._output_path + "/vasprun.xml") else: vasprun = Vasprun("vasprun.xml") except (ET.ParseError, ValueError) as error: results["error"] = error return results for term in results_list: if term == "struct_name": results[term] = self._struct_name elif term == "initial_energy": results[term] = self._get_initial_energy(vasprun) elif term == "total_energy": results[term] = self._get_total_energy(vasprun) elif term == "initial_forces": results[term] = self._get_initial_forces(vasprun) elif term == "final_forces": results[term] = self._get_final_forces(vasprun) elif term == "formula": results[term] = self._struct.formula else: results[term] = "Undefined parameter" return results
def plot_elt_projected_bands(ylim=(-5, 5), fmt="pdf"): """ Plot separate band structures for each element where the size of the markers indicates the elemental character of the eigenvalue. Args: ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun("vasprun.xml", parse_projected_eigen=True) bs = vasprun.get_band_structure("KPOINTS", line_mode=True) bspp = BSPlotterProjected(bs) bspp.get_elt_projected_plots(ylim=ylim).savefig("elt_projected_bands.{}".format(fmt)) plt.close()
def check_symmetry(self): tol_energy = self.get("tol_energy", 0.025) tol_strain = self.get("tol_strain", 0.05) tol_bond = self.get("tol_bond", 0.10) # Get relevant files as pmg objects incar = Incar.from_file("INCAR") vasprun = Vasprun("vasprun.xml") inp_struct = Structure.from_file("POSCAR") out_struct = Structure.from_file("CONTCAR") current_isif = incar['ISIF'] initial_energy = float(vasprun.ionic_steps[0]['e_wo_entrp'])/len(inp_struct) final_energy = float(vasprun.final_energy)/len(out_struct) # perform all symmetry breaking checks failures = [] energy_difference = np.abs(final_energy - initial_energy) if energy_difference > tol_energy: fail_dict = { 'reason': 'energy', 'tolerance': tol_energy, 'value': energy_difference, } failures.append(fail_dict) strain_norm = get_non_isotropic_strain(inp_struct.lattice.matrix, out_struct.lattice.matrix) if strain_norm > tol_strain: fail_dict = { 'reason': 'strain', 'tolerance': tol_strain, 'value': strain_norm, } failures.append(fail_dict) bond_distance_change = get_bond_distance_change(inp_struct, out_struct) if bond_distance_change > tol_bond: fail_dict = { 'reason': 'bond distance', 'tolerance': tol_bond, 'value': bond_distance_change, } failures.append(fail_dict) symm_data = { "initial_structure": inp_struct.as_dict(), "final_structure": out_struct.as_dict(), "isif": current_isif, "initial_energy_per_atom": initial_energy, "final_energy_per_atom": final_energy, "tolerances": { "energy": tol_energy, "strain": tol_strain, "bond": tol_bond, }, "failures": failures, "number_of_failures": len(failures), "symmetry_checks_passed": len(failures) == 0, } return symm_data
def get_runs(vasp_command, target=1e-3, max_steps=10, mode="linear"): """ Generate the runs using a generator until convergence is achieved. """ energy = 0 vinput = VaspInput.from_directory(".") kpoints = vinput["KPOINTS"].kpts[0] for i in range(max_steps): if mode == "linear": m = [k * (i + 1) for k in kpoints] else: m = [k + 1 for k in kpoints] if i == 0: settings = None backup = True else: backup = False v = Vasprun("vasprun.xml") e_per_atom = v.final_energy / len(v.final_structure) ediff = abs(e_per_atom - energy) if ediff < target: logging.info("Converged to {} eV/atom!".format(ediff)) break energy = e_per_atom settings = [ { "dict": "INCAR", "action": { "_set": { "ISTART": 1 } } }, { "dict": "KPOINTS", "action": { "_set": { "kpoints": [m] } } }, { "filename": "CONTCAR", "action": { "_file_copy": { "dest": "POSCAR" } }, }, ] yield VaspJob( vasp_command, final=False, backup=backup, suffix=".kpoints.{}".format("x".join(map(str, m))), settings_override=settings, )
def energy(suffix=''): """ Gets energy for run in current directory :return: """ from pymatgen.io.vasp.outputs import Vasprun v = Vasprun('vasprun.xml' + suffix, parse_dos=False, parse_eigen=False) return v.final_energy
def test_parsing_chemical_shift_calculations(self): with warnings.catch_warnings(): warnings.simplefilter("ignore") filepath = os.path.join(test_dir, "nmr", "cs", "basic", 'vasprun.xml.chemical_shift.scstep') vasprun = Vasprun(filepath) nestep = len(vasprun.ionic_steps[-1]['electronic_steps']) self.assertEqual(nestep, 10) self.assertTrue(vasprun.converged)
def plot_elt_projected_bands(ylim=(-5, 5), fmt='pdf'): """ Plot separate band structures for each element where the size of the markers indicates the elemental character of the eigenvalue. Args: ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun('vasprun.xml', parse_projected_eigen=True) bs = vasprun.get_band_structure('KPOINTS', line_mode=True) bspp = BSPlotterProjected(bs) bspp.get_elt_projected_plots(ylim=ylim).savefig( 'elt_projected_bands.{}'.format(fmt)) plt.close()
def test_update_potcar(self): filepath = os.path.join(test_dir, "vasprun.xml") potcar_path = os.path.join(test_dir, "POTCAR.LiFePO4.gz") potcar_path2 = os.path.join(test_dir, "POTCAR2.LiFePO4.gz") vasprun = Vasprun(filepath, parse_potcar_file=False) self.assertEqual( vasprun.potcar_spec, [ {"titel": "PAW_PBE Li 17Jan2003", "hash": None}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": None}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": None}, {"titel": "PAW_PBE P 17Jan2003", "hash": None}, {"titel": "PAW_PBE O 08Apr2002", "hash": None}, ], ) vasprun.update_potcar_spec(potcar_path) self.assertEqual( vasprun.potcar_spec, [ {"titel": "PAW_PBE Li 17Jan2003", "hash": "65e83282d1707ec078c1012afbd05be8"}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": "9530da8244e4dac17580869b4adab115"}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": "9530da8244e4dac17580869b4adab115"}, {"titel": "PAW_PBE P 17Jan2003", "hash": "7dc3393307131ae67785a0cdacb61d5f"}, {"titel": "PAW_PBE O 08Apr2002", "hash": "7a25bc5b9a5393f46600a4939d357982"}, ], ) vasprun2 = Vasprun(filepath, parse_potcar_file=False) self.assertRaises(ValueError, vasprun2.update_potcar_spec, potcar_path2) vasprun = Vasprun(filepath, parse_potcar_file=potcar_path) self.assertEqual( vasprun.potcar_spec, [ {"titel": "PAW_PBE Li 17Jan2003", "hash": "65e83282d1707ec078c1012afbd05be8"}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": "9530da8244e4dac17580869b4adab115"}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": "9530da8244e4dac17580869b4adab115"}, {"titel": "PAW_PBE P 17Jan2003", "hash": "7dc3393307131ae67785a0cdacb61d5f"}, {"titel": "PAW_PBE O 08Apr2002", "hash": "7a25bc5b9a5393f46600a4939d357982"}, ], ) self.assertRaises(ValueError, Vasprun, filepath, parse_potcar_file=potcar_path2)
def get_band_edges(): """ Calculate the band edge locations relative to the vacuum level for a semiconductor. For a metal, returns the fermi level. Returns: edges (dict): {'up_cbm': , 'up_vbm': , 'dn_cbm': , 'dn_vbm': , 'efermi'} """ # Vacuum level energy from LOCPOT. locpot = Locpot.from_file('LOCPOT') evac = max(locpot.get_average_along_axis(2)) vasprun = Vasprun('vasprun.xml') bs = vasprun.get_band_structure() eigenvals = vasprun.eigenvalues efermi = vasprun.efermi - evac if bs.is_metal(): edges = {'up_cbm': None, 'up_vbm': None, 'dn_cbm': None, 'dn_vbm': None, 'efermi': efermi} elif bs.is_spin_polarized: up_cbm = min( [min([e[0] for e in eigenvals[Spin.up][i] if not e[1]]) for i in range(len(eigenvals[Spin.up]))]) - evac up_vbm = max( [max([e[0] for e in eigenvals[Spin.up][i] if e[1]]) for i in range(len(eigenvals[Spin.up]))]) - evac dn_cbm = min( [min([e[0] for e in eigenvals[Spin.down][i] if not e[1]]) for i in range(len(eigenvals[Spin.down]))]) - evac dn_vbm = max( [max([e[0] for e in eigenvals[Spin.down][i] if e[1]]) for i in range(len(eigenvals[Spin.down]))]) - evac edges = {'up_cbm': up_cbm, 'up_vbm': up_vbm, 'dn_cbm': dn_cbm, 'dn_vbm': dn_vbm, 'efermi': efermi} else: cbm = bs.get_cbm()['energy'] - evac vbm = bs.get_vbm()['energy'] - evac edges = {'up_cbm': cbm, 'up_vbm': vbm, 'dn_cbm': cbm, 'dn_vbm': vbm, 'efermi': efermi} return edges
def test_get_band_structure(self): filepath = os.path.join(test_dir, 'vasprun_Si_bands.xml') vasprun = Vasprun(filepath, parse_potcar_file=False) bs = vasprun.get_band_structure(kpoints_filename= os.path.join(test_dir, 'KPOINTS_Si_bands')) cbm = bs.get_cbm() vbm = bs.get_vbm() self.assertEqual(cbm['kpoint_index'], [13], "wrong cbm kpoint index") self.assertAlmostEqual(cbm['energy'], 6.2301, "wrong cbm energy") self.assertEqual(cbm['band_index'], {Spin.up: [4], Spin.down: [4]}, "wrong cbm bands") self.assertEqual(vbm['kpoint_index'], [0, 63, 64]) self.assertAlmostEqual(vbm['energy'], 5.6158, "wrong vbm energy") self.assertEqual(vbm['band_index'], {Spin.up: [1, 2, 3], Spin.down: [1, 2, 3]}, "wrong vbm bands") self.assertEqual(vbm['kpoint'].label, "\Gamma", "wrong vbm label") self.assertEqual(cbm['kpoint'].label, None, "wrong cbm label")
def optics(ru=''): dirgap, indirgap = get_dir_indir_gap(ru) run = Vasprun( ru, occu_tol=1e-2, ) new_en, new_abs = absorption_coefficient(run.dielectric) return np.array(new_en, dtype=np.float64), np.array( new_abs, dtype=np.float64), dirgap, indirgap
def setUp(self): vasprun_dict = {} for v in glob.glob(os.path.join(get_path(""), "*")): if ".xml.Cu" in v: vasprun_dict[tuple([int(i) for i in v[-6:].strip(".gz") ])] = [Vasprun(v)] self.vasprun_dict = vasprun_dict self.Cu_analyzer = SurfaceEnergyAnalyzer("mp-30", self.vasprun_dict, "Cu")
def set_total_dos_and_volume_from_vasp(self, directory_path: str, vasprun_name: str = "vasprun.xml" ) -> None: vasprun = Vasprun(os.path.join(directory_path, vasprun_name)) # DOS of the sum of all spins. dos = list(vasprun.tdos.get_densities()) energies = list(vasprun.tdos.energies) self._total_dos = [dos, energies] self._volume = vasprun.final_structure.volume
def plot_orb_projected_bands(orbitals, fmt="pdf", ylim=(-5, 5)): """ Plot a separate band structure for each orbital of each element in orbitals. Args: orbitals (dict): dictionary of the form {element: [orbitals]}, e.g. {'Mo': ['s', 'p', 'd'], 'S': ['p']} ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun("vasprun.xml", parse_projected_eigen=True) bs = vasprun.get_band_structure("KPOINTS", line_mode=True) bspp = BSPlotterProjected(bs) bspp.get_projected_plots_dots(orbitals, ylim=ylim).savefig("orb_projected_bands.{}".format(fmt)) plt.close()
def read_convergence_data(self, data_dir): results = {} if 'G0W0' in data_dir or 'GW0' in data_dir or 'scGW0' in data_dir: run = os.path.join(data_dir, 'vasprun.xml') kpoints = os.path.join(data_dir, 'IBZKPT') if os.path.isfile(run): try: logger.debug(run) print(run) data = Vasprun(run, ionic_step_skip=1) parameters = data.incar.as_dict() bandstructure = data.get_band_structure(kpoints) results = {'ecuteps': parameters['ENCUTGW'], 'nbands': parameters['NBANDS'], 'nomega': parameters['NOMEGA'], 'gwgap': bandstructure.get_band_gap()['energy']} print(results) except (IOError, OSError, IndexError, KeyError): pass return results
def from_file(cls, filename): """ Initialize a Bandscape from a vasprun.xml file. Args: filename (str): File in which the Bandscape is stored. Returns: (bandscape.Bandscape) """ return cls(Vasprun(filename))
def __init__(self, waveder_file_ip, outcar_file_ip, vasprun_file_static): """ waveder and outcar files from the linear optical independent particle approximation vasprun file from the associated static calculation """ waveder = Waveder(waveder_file_ip) outcar = Outcar(outcar_file_ip) vasprun = Vasprun(vasprun_file_static) M_norm = norm(waveder.cder_data, axis=-1) * (1e-10 / e) self.M_squared = M_norm * M_norm nelect = round(outcar.nelect) self.vbm_band = nelect // 2 - 1 self.cbm_band = nelect // 2 self.bs = vasprun.get_band_structure() self.nbands = self.bs.nb_bands self.kpoints = self.bs.kpoints self.nkpoints = waveder.nkpoints
def Energy(self): from pymatgen.io.vasp import Vasprun import os os.chdir(self.dire) print(os.getcwd()) v = Vasprun("vasprun.xml") print(v.final_energy) # final total energy s = v.final_structure s.to(filename="relaxed.cif") # save relaxed structure into cif file print(s) # relaxed structure
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_potcar_not_found(self): filepath = os.path.join(test_dir, 'vasprun.xml') #Ensure no potcar is found and nothing is updated with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") vasprun = Vasprun(filepath, parse_potcar_file='.') self.assertEqual(len(w), 1) self.assertEqual(vasprun.potcar_spec, [{"titel": "PAW_PBE Li 17Jan2003", "hash": None}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": None}, {"titel": "PAW_PBE Fe 06Sep2000", "hash": None}, {"titel": "PAW_PBE P 17Jan2003", "hash": None}, {"titel": "PAW_PBE O 08Apr2002", "hash": None}])
def set_band_edge_from_vasp(self, directory_path: str, vasprun_name: str = "vasprun.xml", outcar_name: str = "OUTCAR") -> None: vasprun = Vasprun(os.path.join(directory_path, vasprun_name)) outcar = Outcar(os.path.join(directory_path, outcar_name)) # 2019/7/13 NEVER USE Vasprun.eigenvalue_band_properties # THERE IS A BUG TO ESTIMATE VBM AND CBM of lower band gap materials. _, vbm_info, cbm_info = band_gap_properties(vasprun, outcar) self.is_direct = vbm_info["kpoints"] == cbm_info["kpoints"] self._band_edge = [vbm_info["energy"], cbm_info["energy"]]
def run_task(self, fw_spec): checkpoint_dirs = self.get('checkpoint_dirs') ionic_steps = [] for d in checkpoint_dirs: ionic_steps.extend( Vasprun(os.path.join(d, "vasprun.xml.gz")).ionic_steps) with gzip.open('ionic_steps.json.gz', 'wt', encoding="ascii") as zipfile: json.dump(ionic_steps, zipfile, cls=MontyEncoder)
def plot_orb_projected_bands(orbitals, fmt='pdf', ylim=(-5, 5)): """ Plot a separate band structure for each orbital of each element in orbitals. Args: orbitals (dict): dictionary of the form {element: [orbitals]}, e.g. {'Mo': ['s', 'p', 'd'], 'S': ['p']} ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun('vasprun.xml', parse_projected_eigen=True) bs = vasprun.get_band_structure('KPOINTS', line_mode=True) bspp = BSPlotterProjected(bs) bspp.get_projected_plots_dots(orbitals, ylim=ylim).savefig( 'orb_projected_bands.{}'.format(fmt)) plt.close()
def extract_band_gap(console, table): try: vasprun = Vasprun("vasprun.xml") except: console.print("Unable to locate vasprun.xml") exit() band_gap, cbm, vbm, _ = vasprun.eigenvalue_band_properties fmt = "{:.4f}" table.add_row("Band Gap", fmt.format(band_gap), "eV") table.add_row("Conduction Band Minimum", fmt.format(cbm), "eV") table.add_row("Valence Band Maximum", fmt.format(vbm), "eV")
def get_minimum_energy_job(pwd): min_energy = 1000 for root, dirs, files in os.walk(pwd): for file in files: if file == 'POTCAR' and check_vasp_input(root) == True: Vr = Vasprun(os.path.join(root, 'vasprun.xml')) nsites = len(Vr.final_structure) E_per_atom = Vr.final_energy / nsites if E_per_atom < min_energy: min_energy = E_per_atom job_path = root return job_path
def tabluateitall(workdir): import os from operator import itemgetter import pandas as pd from pymatgen import Structure from pymatgen.io.vasp.outputs import Vasprun data = [] for subdir, dirs, files in os.walk(workdir): for file in files: if file.endswith('OUTCAR'): try: print(subdir.replace(workdir, '')) file_pos = Structure.from_file(subdir + '/POSCAR') file_vr = Vasprun(subdir + '/vasprun.xml') # Add things to a list data.append([ subdir.replace(workdir, ''), file_pos.composition, file_pos.composition.num_atoms, file_vr.final_energy, file_vr.final_energy / file_pos.composition.num_atoms, file_vr.converged ]) except BadPotcarWarning: data.append([ subdir.replace(workdir, ''), file_pos.composition, file_pos.composition.num_atoms, '!!!', '!!!', 'badpotcar?', 'FLAG RAISED' ]) except: data.append([ subdir.replace(workdir, ''), file_pos.composition, file_pos.composition.num_atoms, file_vr.final_energy, file_vr.final_energy / file_pos.composition.num_atoms, '!!!', 'FLAG RAISED' ]) print( 'STUPID ERROR - pymatgen doesnt like your outcar or vasprun ??? - Are all jobs complete?' ) pass data = sorted(data, key=itemgetter(0)) TITLE = [ 'FOLDER NAME', 'COMPOSITION', 'NO. ATOMS', 'TOTAL ENERGY', 'ENERGY / ATOM', 'CHECK_CONV RESULT', 'FLAGS?' ] data = [[TITLE], data] data = [item for sublist in data for item in sublist] datadf = pd.DataFrame(data) writer = pd.ExcelWriter(workdir + '/TABSFROMRUNS.xlsx') datadf.to_excel(writer) writer.save()
def plot_color_projected_bands(ylim=(-5, 5), fmt="pdf"): """ Plot a single band structure where the color of the band indicates the elemental character of the eigenvalue. Args: ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun("vasprun.xml", parse_projected_eigen=True) bs = vasprun.get_band_structure("KPOINTS", line_mode=True) bspp = BSPlotterProjected(bs) plot = bspp.get_elt_projected_plots_color() fig = plot.gcf() ax = fig.gca() ax.set_xticklabels([r"$\mathrm{%s}$" % t for t in ax.get_xticklabels()]) ax.set_ylim(ylim) fig.savefig("color_projected_bands.{}".format(fmt)) plt.close()
def plot_elt_projected_bands(ylim=(-5, 5), fmt='pdf'): """ Plot separate band structures for each element where the size of the markers indicates the elemental character of the eigenvalue. Args: ylim (tuple): minimum and maximum energies for the plot's y-axis. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun('vasprun.xml', parse_projected_eigen=True) bs = vasprun.get_band_structure('KPOINTS', line_mode=True) bspp = BSPlotterProjected(bs) ax = bspp.get_elt_projected_plots(ylim=ylim).gcf().gca() ax.set_xticklabels([r'$\mathrm{%s}$' % t for t in ax.get_xticklabels()]) ax.set_yticklabels([r'$\mathrm{%s}$' % t for t in ax.get_yticklabels()]) if fmt == "None": return ax else: plt.savefig('elt_projected_bands.{}'.format(fmt)) plt.close()
def get_fermi_velocities(): """ Calculates the fermi velocity of each band that crosses the fermi level, according to v_F = dE/(h_bar*dk). Returns: fermi_velocities (list). The absolute values of the adjusted slopes of each band, in Angstroms/s. """ vr = Vasprun('vasprun.xml') # eigenvalues = vr.eigenvalues bs = vr.get_band_structure() bands = bs.bands kpoints = bs.kpoints efermi = bs.efermi h_bar = 6.582e-16 # eV*s fermi_bands = [] for spin in bands: for i in range(len(bands[spin])): if max(bands[spin][i]) > efermi > min(bands[spin][i]): fermi_bands.append(bands[spin][i]) fermi_velocities = [] for band in fermi_bands: for i in range(len(band)-1): if (band[i] < efermi < band[i+1]) or (band[i] > efermi > band[i+1]): dk = np.sqrt((kpoints[i+1].cart_coords[0] - kpoints[i].cart_coords[0])**2 + (kpoints[i+1].cart_coords[1] - kpoints[i].cart_coords[1])**2) v_f = abs((band[i+1] - band[i]) / (h_bar * dk)) fermi_velocities.append(v_f) return fermi_velocities # Values are in Angst./s
def plot_band_structure(ylim=(-5, 5), draw_fermi=False, fmt="pdf"): """ Plot a standard band structure with no projections. Args: ylim (tuple): minimum and maximum potentials for the plot's y-axis. draw_fermi (bool): whether or not to draw a dashed line at E_F. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ vasprun = Vasprun("vasprun.xml") efermi = vasprun.efermi bsp = BSPlotter(vasprun.get_band_structure("KPOINTS", line_mode=True, efermi=efermi)) plot = bsp.get_plot(ylim=ylim) fig = plot.gcf() ax = fig.gca() ax.set_xticklabels([r"$\mathrm{%s}$" % t for t in ax.get_xticklabels()]) if draw_fermi: ax.plot([ax.get_xlim()[0], ax.get_xlim()[1]], [0, 0], "k--") fig.savefig("band_structure.{}".format(fmt), transparent=True) plt.close()
def assimilate(self, path, launches_coll=None): """ Parses vasp runs. Then insert the result into the db. and return the task_id or doc of the insertion. Returns: If in simulate_mode, the entire doc is returned for debugging purposes. Else, only the task_id of the inserted doc is returned. """ d = self.get_task_doc(path) if self.additional_fields: d.update(self.additional_fields) # always add additional fields, even for failed jobs try: d["dir_name_full"] = d["dir_name"].split(":")[1] d["dir_name"] = get_block_part(d["dir_name_full"]) d["stored_data"] = {} except: print 'COULD NOT GET DIR NAME' pprint.pprint(d) print traceback.format_exc() raise ValueError('IMPROPER PARSING OF {}'.format(path)) if not self.simulate: # Perform actual insertion into db. Because db connections cannot # be pickled, every insertion needs to create a new connection # to the db. conn = MongoClient(self.host, self.port) db = conn[self.database] if self.user: db.authenticate(self.user, self.password) coll = db[self.collection] # Insert dos data into gridfs and then remove it from the dict. # DOS data tends to be above the 4Mb limit for mongo docs. A ref # to the dos file is in the dos_fs_id. result = coll.find_one({"dir_name": d["dir_name"]}) if result is None or self.update_duplicates: if self.parse_dos and "calculations" in d: for calc in d["calculations"]: if "dos" in calc: dos = json.dumps(calc["dos"], cls=MontyEncoder) fs = gridfs.GridFS(db, "dos_fs") dosid = fs.put(dos) calc["dos_fs_id"] = dosid del calc["dos"] d["last_updated"] = datetime.datetime.today() if result is None: if ("task_id" not in d) or (not d["task_id"]): d["task_id"] = "mp-{}".format( db.counter.find_one_and_update( {"_id": "taskid"}, {"$inc": {"c": 1}} )["c"]) logger.info("Inserting {} with taskid = {}" .format(d["dir_name"], d["task_id"])) elif self.update_duplicates: d["task_id"] = result["task_id"] logger.info("Updating {} with taskid = {}" .format(d["dir_name"], d["task_id"])) #Fireworks processing self.process_fw(path, d) try: #Add oxide_type struct=Structure.from_dict(d["output"]["crystal"]) d["oxide_type"]=oxide_type(struct) except: logger.error("can't get oxide_type for {}".format(d["task_id"])) d["oxide_type"] = None #Override incorrect outcar subdocs for two step relaxations if "optimize structure" in d['task_type'] and \ os.path.exists(os.path.join(path, "relax2")): try: run_stats = {} for i in [1,2]: o_path = os.path.join(path,"relax"+str(i),"OUTCAR") o_path = o_path if os.path.exists(o_path) else o_path+".gz" outcar = Outcar(o_path) d["calculations"][i-1]["output"]["outcar"] = outcar.as_dict() run_stats["relax"+str(i)] = outcar.run_stats except: logger.error("Bad OUTCAR for {}.".format(path)) try: overall_run_stats = {} for key in ["Total CPU time used (sec)", "User time (sec)", "System time (sec)", "Elapsed time (sec)"]: overall_run_stats[key] = sum([v[key] for v in run_stats.values()]) run_stats["overall"] = overall_run_stats except: logger.error("Bad run stats for {}.".format(path)) d["run_stats"] = run_stats # add is_compatible mpc = MaterialsProjectCompatibility("Advanced") try: func = d["pseudo_potential"]["functional"] labels = d["pseudo_potential"]["labels"] symbols = ["{} {}".format(func, label) for label in labels] parameters = {"run_type": d["run_type"], "is_hubbard": d["is_hubbard"], "hubbards": d["hubbards"], "potcar_symbols": symbols} entry = ComputedEntry(Composition(d["unit_cell_formula"]), 0.0, 0.0, parameters=parameters, entry_id=d["task_id"]) d['is_compatible'] = bool(mpc.process_entry(entry)) except: traceback.print_exc() print 'ERROR in getting compatibility' d['is_compatible'] = None #task_type dependent processing if 'static' in d['task_type']: launch_doc = launches_coll.find_one({"fw_id": d['fw_id'], "launch_dir": {"$regex": d["dir_name"]}}, {"action.stored_data": 1}) for i in ["conventional_standard_structure", "symmetry_operations", "symmetry_dataset", "refined_structure"]: try: d['stored_data'][i] = launch_doc['action']['stored_data'][i] except: pass #parse band structure if necessary if ('band structure' in d['task_type'] or "Uniform" in d['task_type'])\ and d['state'] == 'successful': launch_doc = launches_coll.find_one({"fw_id": d['fw_id'], "launch_dir": {"$regex": d["dir_name"]}}, {"action.stored_data": 1}) vasp_run = Vasprun(zpath(os.path.join(path, "vasprun.xml")), parse_projected_eigen=False) if 'band structure' in d['task_type']: def string_to_numlist(stringlist): g=re.search('([0-9\-\.eE]+)\s+([0-9\-\.eE]+)\s+([0-9\-\.eE]+)', stringlist) return [float(g.group(i)) for i in range(1,4)] for i in ["kpath_name", "kpath"]: d['stored_data'][i] = launch_doc['action']['stored_data'][i] kpoints_doc = d['stored_data']['kpath']['kpoints'] for i in kpoints_doc: kpoints_doc[i]=string_to_numlist(kpoints_doc[i]) bs=vasp_run.get_band_structure(efermi=d['calculations'][0]['output']['outcar']['efermi'], line_mode=True) else: bs=vasp_run.get_band_structure(efermi=d['calculations'][0]['output']['outcar']['efermi'], line_mode=False) bs_json = json.dumps(bs.as_dict(), cls=MontyEncoder) fs = gridfs.GridFS(db, "band_structure_fs") bs_id = fs.put(bs_json) d['calculations'][0]["band_structure_fs_id"] = bs_id # also override band gap in task doc gap = bs.get_band_gap() vbm = bs.get_vbm() cbm = bs.get_cbm() update_doc = {'bandgap': gap['energy'], 'vbm': vbm['energy'], 'cbm': cbm['energy'], 'is_gap_direct': gap['direct']} d['analysis'].update(update_doc) d['calculations'][0]['output'].update(update_doc) coll.update_one({"dir_name": d["dir_name"]}, {'$set': d}, upsert=True) return d["task_id"], d else: logger.info("Skipping duplicate {}".format(d["dir_name"])) return result["task_id"], result else: d["task_id"] = 0 logger.info("Simulated insert into database for {} with task_id {}" .format(d["dir_name"], d["task_id"])) return 0, d
lc = LineCollection(seg, colors=list(zip(r, g, b, a)), linewidth=2) ax.add_collection(lc) if __name__ == "__main__": # read data # --------- # kpoints labels labels = [r"$L$", r"$\Gamma$", r"$X$", r"$U,K$", r"$\Gamma$"] # density of states dosrun = Vasprun("./DOS/vasprun.xml") spd_dos = dosrun.complete_dos.get_spd_dos() # bands run = Vasprun("./Bandes/vasprun.xml", parse_projected_eigen=True) bands = run.get_band_structure("./Bandes/KPOINTS", line_mode=True, efermi=dosrun.efermi) # set up matplotlib plot # ---------------------- # general options for plot font = {'family': 'serif', 'size': 24} plt.rc('font', **font) # set up 2 graph with aspec ration 2/1 # plot 1: bands diagram # plot 2: Density of States gs = GridSpec(1, 2, width_ratios=[2, 1])
seg = np.concatenate([pts[:-1], pts[1:]], axis=1) nseg = len(k)-1 r = [0.5*(red[i]+red[i+1]) for i in range(nseg)] g = [0.5*(green[i]+green[i+1]) for i in range(nseg)] b = [0.5*(blue[i]+blue[i+1]) for i in range(nseg)] a = np.ones(nseg, np.float)*alpha lc = LineCollection(seg, colors=zip(r,g,b,a), linewidth = 2) ax.add_collection(lc) if __name__ == "__main__": # -------------------------------------------------------------- # read data # -------------------------------------------------------------- # readin bandstructure and density of states from vasprun.xml file run = Vasprun("vasprun.xml", parse_projected_eigen = True) bands = run.get_band_structure("KPOINTS", line_mode = True, efermi = run.efermi) complete_dos = run.complete_dos print 'cbm and vbm ', complete_dos.get_cbm_vbm() print 'gap = ', complete_dos.get_gap() # get orbital projected DOS. spd_dos = complete_dos.get_spd_dos() # kpoints labels, must conform with the label in the KPOINTS file labels = [ r"$G$", r"$X$", r"$M$", r"$G$"] # -------------------------------------------------------------- # compute a dictionary of projections on elements and specific orbitals #A dictionary of Elements and Orbitals for which we want #to have projections on. It is given as: {Element:[orbitals]}, #e.g., {'Cu':['d','s']} # --------------------------------------------------------------
def plot_band_alignments(directories, run_type='PBE', fmt='pdf'): """ Plot CBM's and VBM's of all compounds together, relative to the band edges of H2O. Args: directories (list): list of the directory paths for materials to include in the plot. run_type (str): 'PBE' or 'HSE', so that the function knows which subdirectory to go into (pbe_bands or hse_bands). fmt (str): matplotlib format style. Check the matplotlib docs for options. """ if run_type == 'HSE': subdirectory = 'hse_bands' else: subdirectory = 'pbe_bands' band_gaps = {} for directory in directories: sub_dir = os.path.join(directory, subdirectory) if is_converged(sub_dir): os.chdir(sub_dir) band_structure = Vasprun('vasprun.xml').get_band_structure() band_gap = band_structure.get_band_gap() # Vacuum level energy from LOCPOT. locpot = Locpot.from_file('LOCPOT') evac = max(locpot.get_average_along_axis(2)) if not band_structure.is_metal(): is_direct = band_gap['direct'] cbm = band_structure.get_cbm() vbm = band_structure.get_vbm() else: cbm = None vbm = None is_direct = False band_gaps[directory] = {'CBM': cbm, 'VBM': vbm, 'Direct': is_direct, 'Metal': band_structure.is_metal(), 'E_vac': evac} os.chdir('../../') ax = plt.figure(figsize=(16, 10)).gca() x_max = len(band_gaps) * 1.315 ax.set_xlim(0, x_max) # Rectangle representing band edges of water. ax.add_patch(plt.Rectangle((0, -5.67), height=1.23, width=len(band_gaps), facecolor='#00cc99', linewidth=0)) ax.text(len(band_gaps) * 1.01, -4.44, r'$\mathrm{H+/H_2}$', size=20, verticalalignment='center') ax.text(len(band_gaps) * 1.01, -5.67, r'$\mathrm{O_2/H_2O}$', size=20, verticalalignment='center') x_ticklabels = [] y_min = -8 i = 0 # Nothing but lies. are_directs, are_indirects, are_metals = False, False, False for compound in [cpd for cpd in directories if cpd in band_gaps]: x_ticklabels.append(compound) # Plot all energies relative to their vacuum level. evac = band_gaps[compound]['E_vac'] if band_gaps[compound]['Metal']: cbm = -8 vbm = -2 else: cbm = band_gaps[compound]['CBM']['energy'] - evac vbm = band_gaps[compound]['VBM']['energy'] - evac # Add a box around direct gap compounds to distinguish them. if band_gaps[compound]['Direct']: are_directs = True linewidth = 5 elif not band_gaps[compound]['Metal']: are_indirects = True linewidth = 0 # Metals are grey. if band_gaps[compound]['Metal']: are_metals = True linewidth = 0 color_code = '#404040' else: color_code = '#002b80' # CBM ax.add_patch(plt.Rectangle((i, cbm), height=-cbm, width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) # VBM ax.add_patch(plt.Rectangle((i, y_min), height=(vbm - y_min), width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) i += 1 ax.set_ylim(y_min, 0) # Set tick labels ax.set_xticks([n + 0.4 for n in range(i)]) ax.set_xticklabels(x_ticklabels, family='serif', size=20, rotation=60) ax.set_yticklabels(ax.get_yticks(), family='serif', size=20) # Add a legend height = y_min if are_directs: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#002b80', edgecolor='#e68a00', linewidth=5)) ax.text(i*1.24, height - y_min * 0.05, 'Direct', family='serif', color='w', size=20, horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_indirects: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#002b80', linewidth=0)) ax.text(i*1.24, height - y_min * 0.05, 'Indirect', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_metals: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#404040', linewidth=0)) ax.text(i*1.24, height - y_min * 0.05, 'Metal', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') # Who needs axes? ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_visible(False) ax.spines['left'].set_visible(False) ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') ax.set_ylabel('eV', family='serif', size=24) if fmt == "None": return ax else: plt.savefig('band_alignments.{}'.format(fmt), transparent=True) plt.close()
def plot_band_alignments(directories, run_type="PBE", fmt="pdf"): """ Plot CBM's and VBM's of all compounds together, relative to the band edges of H2O. Args: directories (list): list of the directory paths for materials to include in the plot. run_type (str): 'PBE' or 'HSE', so that the function knows which subdirectory to go into (pbe_bands or hse_bands). fmt (str): matplotlib format style. Check the matplotlib docs for options. """ if run_type == "HSE": subdirectory = "hse_bands" else: subdirectory = "pbe_bands" band_gaps = {} for directory in directories: if is_converged("{}/{}".format(directory, subdirectory)): os.chdir("{}/{}".format(directory, subdirectory)) band_structure = Vasprun("vasprun.xml").get_band_structure() band_gap = band_structure.get_band_gap() # Vacuum level energy from LOCPOT. locpot = Locpot.from_file("LOCPOT") evac = max(locpot.get_average_along_axis(2)) try: is_metal = False is_direct = band_gap["direct"] cbm = band_structure.get_cbm() vbm = band_structure.get_vbm() except AttributeError: cbm = None vbm = None is_metal = True is_direct = False band_gaps[directory] = {"CBM": cbm, "VBM": vbm, "Direct": is_direct, "Metal": is_metal, "E_vac": evac} os.chdir("../../") ax = plt.figure(figsize=(16, 10)).gca() x_max = len(band_gaps) * 1.315 ax.set_xlim(0, x_max) # Rectangle representing band edges of water. ax.add_patch(plt.Rectangle((0, -5.67), height=1.23, width=len(band_gaps), facecolor="#00cc99", linewidth=0)) ax.text(len(band_gaps) * 1.01, -4.44, r"$\mathrm{H+/H_2}$", size=20, verticalalignment="center") ax.text(len(band_gaps) * 1.01, -5.67, r"$\mathrm{O_2/H_2O}$", size=20, verticalalignment="center") x_ticklabels = [] y_min = -8 i = 0 # Nothing but lies. are_directs, are_indirects, are_metals = False, False, False for compound in [cpd for cpd in directories if cpd in band_gaps]: x_ticklabels.append(compound) # Plot all energies relative to their vacuum level. evac = band_gaps[compound]["E_vac"] if band_gaps[compound]["Metal"]: cbm = -8 vbm = -2 else: cbm = band_gaps[compound]["CBM"]["energy"] - evac vbm = band_gaps[compound]["VBM"]["energy"] - evac # Add a box around direct gap compounds to distinguish them. if band_gaps[compound]["Direct"]: are_directs = True linewidth = 5 elif not band_gaps[compound]["Metal"]: are_indirects = True linewidth = 0 # Metals are grey. if band_gaps[compound]["Metal"]: are_metals = True linewidth = 0 color_code = "#404040" else: color_code = "#002b80" # CBM ax.add_patch( plt.Rectangle( (i, cbm), height=-cbm, width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00" ) ) # VBM ax.add_patch( plt.Rectangle( (i, y_min), height=(vbm - y_min), width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00", ) ) i += 1 ax.set_ylim(y_min, -2) # Set tick labels ax.set_xticks([n + 0.4 for n in range(i)]) ax.set_xticklabels(x_ticklabels, family="serif", size=20, rotation=60) ax.set_yticklabels(ax.get_yticks(), family="serif", size=20) # Add a legend height = y_min if are_directs: ax.add_patch( plt.Rectangle( (i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor="#002b80", edgecolor="#e68a00", linewidth=5, ) ) ax.text( i * 1.24, height - y_min * 0.05, "Direct", family="serif", color="w", size=20, horizontalalignment="center", verticalalignment="center", ) height -= y_min * 0.15 if are_indirects: ax.add_patch( plt.Rectangle((i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor="#002b80", linewidth=0) ) ax.text( i * 1.24, height - y_min * 0.05, "Indirect", family="serif", size=20, color="w", horizontalalignment="center", verticalalignment="center", ) height -= y_min * 0.15 if are_metals: ax.add_patch( plt.Rectangle((i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor="#404040", linewidth=0) ) ax.text( i * 1.24, height - y_min * 0.05, "Metal", family="serif", size=20, color="w", horizontalalignment="center", verticalalignment="center", ) # Who needs axes? ax.spines["top"].set_visible(False) ax.spines["right"].set_visible(False) ax.spines["bottom"].set_visible(False) ax.spines["left"].set_visible(False) ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") ax.set_ylabel("eV", family="serif", size=24) plt.savefig("band_alignments.{}".format(fmt), transparent=True) plt.close()
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
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 get_effective_mass(): """ This function is in a beta stage, and its results are not guaranteed to be useful. Finds effective masses from a band structure, using parabolic fitting to determine the band curvature at the CBM for electrons and at the VBM for holes. This curvature enters the equation m* = (hbar)**2 / (d^2E/dk^2). To consider anisotropy, the k-space directions to the left and right of the CBM/VBM in the band diagram are returned separately. *NOTE* Only works for semiconductors and linemode calculations (non- spin polarized). >30 k-points per string recommended to obtain reliable curvatures. *NOTE* The parabolic fit can be quite sensitive to the number of k-points fit to, so it might be worthwhile adjusting N_KPTS to obtain some sense of the error bar. TODO: Warn user if CBM/VBM is at the edge of the diagram, and which direction (either left or right) was not actually fit to. Until fixed, this (most likely) explains any negative masses returned. Returns: Dictionary of the form {'electron': {'left': e_m_eff_l, 'right': e_m_eff_r}, 'hole': {'left': h_m_eff_l, 'right': h_m_eff_r}} where 'left' and 'right' indicate the reciprocal directions to the left and right of the extremum in the band structure. """ H_BAR = 6.582119514e-16 # eV*s M_0 = 9.10938356e-31 # kg N_KPTS = 6 # Number of k-points included in the parabola. spin_up = Spin(1) band_structure = Vasprun('vasprun.xml').get_band_structure() # Locations of CBM and VBM in band_structure.bands cbm_band_index = band_structure.get_cbm()['band_index'][spin_up][0] cbm_kpoint_index = band_structure.get_cbm()['kpoint_index'][0] vbm_band_index = band_structure.get_vbm()['band_index'][spin_up][0] vbm_kpoint_index = band_structure.get_vbm()['kpoint_index'][0] k = {'electron': {'left': [], 'right': []}, 'hole': {'left': [], 'right': []}} E = {'electron': {'left': [], 'right': []}, 'hole': {'left': [], 'right': []}} e_ref_coords = band_structure.kpoints[cbm_kpoint_index]._ccoords h_ref_coords = band_structure.kpoints[vbm_kpoint_index]._ccoords for n in range(-N_KPTS, 1): e_coords = band_structure.kpoints[cbm_kpoint_index + n]._ccoords h_coords = band_structure.kpoints[vbm_kpoint_index + n]._ccoords k['electron']['left'].append( ((e_coords[0] - e_ref_coords[0])**2 + (e_coords[1] - e_ref_coords[1])**2 + (e_coords[2] - e_ref_coords[2])**2)**0.5 ) k['hole']['left'].append( ((h_coords[0] - h_ref_coords[0])**2 + (h_coords[1] - h_ref_coords[1])**2 + (h_coords[2] - h_ref_coords[2])**2)**0.5 ) e_energy = band_structure.bands[ spin_up][cbm_band_index][cbm_kpoint_index + n] h_energy = band_structure.bands[ spin_up][vbm_band_index][vbm_kpoint_index + n] E['electron']['left'].append(e_energy) E['hole']['left'].append(h_energy) for n in range(1, 1 + N_KPTS): e_coords = band_structure.kpoints[cbm_kpoint_index + n]._ccoords h_coords = band_structure.kpoints[vbm_kpoint_index + n]._ccoords k['electron']['right'].append( ((e_coords[0] - e_ref_coords[0])**2 + (e_coords[1] - e_ref_coords[1])**2 + (e_coords[2] - e_ref_coords[2])**2)**0.5 ) k['hole']['right'].append( ((h_coords[0] - h_ref_coords[0])**2 + (h_coords[1] - h_ref_coords[1])**2 + (h_coords[2] - h_ref_coords[2])**2)**0.5 ) e_energy = band_structure.bands[ spin_up][cbm_band_index][cbm_kpoint_index + n] h_energy = band_structure.bands[ spin_up][vbm_band_index][vbm_kpoint_index + n] E['electron']['right'].append(e_energy) E['hole']['right'].append(h_energy) # 2nd order fits e_l_fit = np.poly1d( np.polyfit(k['electron']['left'], E['electron']['left'], 2)) e_r_fit = np.poly1d( np.polyfit(k['electron']['right'], E['electron']['right'], 2)) h_l_fit = np.poly1d( np.polyfit(k['hole']['left'], E['hole']['left'], 2)) h_r_fit = np.poly1d( np.polyfit(k['hole']['right'], E['hole']['right'], 2)) # Curvatures e_l_curvature = e_l_fit.deriv().deriv()[0] e_r_curvature = e_r_fit.deriv().deriv()[0] h_l_curvature = h_l_fit.deriv().deriv()[0] h_r_curvature = h_r_fit.deriv().deriv()[0] # Unit conversion e_m_eff_l = 10 * ((H_BAR ** 2) / e_l_curvature) / M_0 e_m_eff_r = 10 * ((H_BAR ** 2) / e_r_curvature) / M_0 h_m_eff_l = -10 * ((H_BAR ** 2) / h_l_curvature) / M_0 h_m_eff_r = -10 * ((H_BAR ** 2) / h_r_curvature) / M_0 return {'electron': {'left': e_m_eff_l, 'right': e_m_eff_r}, 'hole': {'left': h_m_eff_l, 'right': h_m_eff_r}}