encut=240, ismear=0, sigma=0.1, nbands=20, icharg=11, lorbit=11, kspacing=1) Si3.set_calculator(calc3) en3 = Si2.get_potential_energy() # *************************************************************************************************** os.chdir('..') dosrun = Vasprun("DOS/vasprun.xml", parse_dos=True) dos = dosrun.complete_dos print("E_Fermi=%f%3s" % (dosrun.efermi, 'eV')) # print(dos.efermi) dosplot1 = DosPlotter(sigma=0.05) dosplot1.add_dos("Total DOS", dos) plt = dosplot1.get_plot(xlim=(-18, 15)) plt.grid() plt.savefig("pymatgen_DOS.eps", format="eps") plt.show() plt.close() # bsrun = BSVasprun("Band/vasprun.xml", parse_projected_eigen=True) bsrun = BSVasprun("Band/vasprun.xml")
def constrained_opt_run(cls, vasp_cmd, lattice_direction, initial_strain, atom_relax=True, max_steps=20, algo="bfgs", **vasp_job_kwargs): """ Returns a generator of jobs for a constrained optimization run. Typical use case is when you want to approximate a biaxial strain situation, e.g., you apply a defined strain to a and b directions of the lattice, but allows the c-direction to relax. Some guidelines on the use of this method: i. It is recommended you do not use the Auto kpoint generation. The grid generated via Auto may fluctuate with changes in lattice param, resulting in numerical noise. ii. Make sure your EDIFF/EDIFFG is properly set in your INCAR. The optimization relies on these values to determine convergence. Args: vasp_cmd (str): Command to run vasp as a list of args. For example, if you are using mpirun, it can be something like ["mpirun", "pvasp.5.2.11"] lattice_direction (str): Which direction to relax. Valid values are "a", "b" or "c". initial_strain (float): An initial strain to be applied to the lattice_direction. This can usually be estimated as the negative of the strain applied in the other two directions. E.g., if you apply a tensile strain of 0.05 to the a and b directions, you can use -0.05 as a reasonable first guess for initial strain. atom_relax (bool): Whether to relax atomic positions. max_steps (int): The maximum number of runs. Defaults to 20 ( highly unlikely that this limit is ever reached). algo (str): Algorithm to use to find minimum. Default is "bfgs", which is fast, but can be sensitive to numerical noise in energy calculations. The alternative is "bisection", which is more robust but can be a bit slow. The code does fall back on the bisection when bfgs gives a non-sensical result, e.g., negative lattice params. \*\*vasp_job_kwargs: Passthrough kwargs to VaspJob. See :class:`custodian.vasp.jobs.VaspJob`. Returns: Generator of jobs. At the end of the run, an "EOS.txt" is written which provides a quick look at the E vs lattice parameter. """ nsw = 99 if atom_relax else 0 incar = Incar.from_file("INCAR") # Set the energy convergence criteria as the EDIFFG (if present) or # 10 x EDIFF (which itself defaults to 1e-4 if not present). if incar.get("EDIFFG") and incar.get("EDIFFG") > 0: etol = incar["EDIFFG"] else: etol = incar.get("EDIFF", 1e-4) * 10 if lattice_direction == "a": lattice_index = 0 elif lattice_direction == "b": lattice_index = 1 else: lattice_index = 2 energies = {} for i in range(max_steps): if i == 0: settings = [{ "dict": "INCAR", "action": { "_set": { "ISIF": 2, "NSW": nsw } } }] structure = Poscar.from_file("POSCAR").structure x = structure.lattice.abc[lattice_index] backup = True else: backup = False v = Vasprun("vasprun.xml") structure = v.final_structure energy = v.final_energy lattice = structure.lattice x = lattice.abc[lattice_index] energies[x] = energy if i == 1: x *= 1 + initial_strain else: # Sort the lattice parameter by energies. min_x = min(energies.keys(), key=lambda e: energies[e]) sorted_x = sorted(energies.keys()) ind = sorted_x.index(min_x) if ind == 0: other = ind + 1 elif ind == len(sorted_x) - 1: other = ind - 1 else: other = (ind + 1 if energies[sorted_x[ind + 1]] < energies[sorted_x[ind - 1]] else ind - 1) if abs(energies[min_x] - energies[sorted_x[other]]) < etol: logger.info("Stopping optimization! Final %s = %f" % (lattice_direction, min_x)) break if ind == 0 and len(sorted_x) > 2: # Lowest energy lies outside of range of lowest value. # we decrease the lattice parameter in the next # iteration to find a minimum. This applies only when # there are at least 3 values. x = sorted_x[0] - abs(sorted_x[1] - sorted_x[0]) logger.info("Lowest energy lies below bounds. " "Setting %s = %f." % (lattice_direction, x)) elif ind == len(sorted_x) - 1 and len(sorted_x) > 2: # Lowest energy lies outside of range of highest value. # we increase the lattice parameter in the next # iteration to find a minimum. This applies only when # there are at least 3 values. x = sorted_x[-1] + abs(sorted_x[-1] - sorted_x[-2]) logger.info("Lowest energy lies above bounds. " "Setting %s = %f." % (lattice_direction, x)) else: if algo.lower() == "bfgs" and len(sorted_x) >= 4: try: # If there are more than 4 data points, we will # do a quadratic fit to accelerate convergence. x1 = list(energies.keys()) y1 = [energies[j] for j in x1] z1 = np.polyfit(x1, y1, 2) pp = np.poly1d(z1) from scipy.optimize import minimize result = minimize(pp, min_x, bounds=[(sorted_x[0], sorted_x[-1])]) if (not result.success) or result.x[0] < 0: raise ValueError( "Negative lattice constant!") x = result.x[0] logger.info("BFGS minimized %s = %f." % (lattice_direction, x)) except ValueError as ex: # Fall back on bisection algo if the bfgs fails. logger.info(str(ex)) x = (min_x + sorted_x[other]) / 2 logger.info( "Falling back on bisection %s = %f." % (lattice_direction, x)) else: x = (min_x + sorted_x[other]) / 2 logger.info("Bisection %s = %f." % (lattice_direction, x)) lattice = lattice.matrix lattice[lattice_index] = ( lattice[lattice_index] / np.linalg.norm(lattice[lattice_index]) * x) s = Structure(lattice, structure.species, structure.frac_coords) fname = "POSCAR.%f" % x s.to(filename=fname) incar_update = {"ISTART": 1, "NSW": nsw, "ISIF": 2} settings = [ { "dict": "INCAR", "action": { "_set": incar_update } }, { "file": fname, "action": { "_file_copy": { "dest": "POSCAR" } } }, ] logger.info("Generating job = %d with parameter %f!" % (i + 1, x)) yield VaspJob(vasp_cmd, final=False, backup=backup, suffix=".static.%f" % x, settings_override=settings, **vasp_job_kwargs) with open("EOS.txt", "wt") as f: f.write("# %s energy\n" % lattice_direction) for k in sorted(energies.keys()): f.write("%f %f\n" % (k, energies[k]))
#!/usr/bin/env python # -*- coding=utf-8 -*- import matplotlib.pyplot as plt from matplotlib.ticker import MultipleLocator from pymatgen.electronic_structure.core import Spin from pymatgen.io.vasp.outputs import Vasprun if __name__ == "__main__": vasprun_dirctory = '/mnt/c/Users/a/OneDrive/Calculation_Data/Mg2C_Graphene/Paper_results/Bands/data/' vasprun_file = 'vasprun.xml' kpoints_file = 'KPOINTS' saving_dictory = '/mnt/c/Users/a/OneDrive/Calculation_Data/Mg2C_Graphene/Paper_results/Picture/' saving_file = '{}'.format('TotBand') title = '{}'.format(r"$Mg_2C$" + '-Gr' + ' TotBand') vasprun = Vasprun("{}".format(vasprun_dirctory + vasprun_file)) bands = vasprun.get_band_structure("{}".format(vasprun_dirctory + kpoints_file), line_mode=True, efermi=vasprun.efermi) energy_min = -1 energy_max = 1 # 高对称点设置 labels = [r"$M$", r"$\Gamma$", r"$K$", r"$M$"] labels_position = list() font = {'family': 'sans-serif', 'size': 24} # 开始画图 fig, ax1 = plt.subplots(figsize=(16, 10)) # 设置刻度向内 ax1.tick_params(direction='in')
def test_Xe(self): vr = Vasprun(os.path.join(test_dir, 'vasprun.xml.xe'), parse_potcar_file=False) self.assertEqual(vr.atomic_symbols, ['Xe'])
def test_vdw(self): v = Vasprun(os.path.join(test_dir, "vasprun.xml.vdw")) self.assertAlmostEqual(v.final_energy, -9.78310677)
def setUp(self): vr = Vasprun(example_dir / "MgB2/vasprun.xml") bs = vr.get_band_structure() self.band_structure = bs self.output_file = test_dir / "fs.png"
from pymatgen.electronic_structure.dos import add_densities from pymatgen.io.vasp.outputs import Vasprun, Dos from pymatgen.electronic_structure.plotter import DosPlotter import six import os from VASP.vasprun_related.utiles import write_dos import numpy as np os.chdir('/home/jinho93/oxides/cluster/tio2/anatase/dos') vrun = Vasprun('vasprun.xml') cdos = vrun.complete_dos arr = [] arr2 = [] num = 0 num2 = 0 for i in vrun.final_structure.sites: if 0.425 < i.a < 0.575 and 0.425 < i.b < 0.575 and 0.42 < i.c < 0.58: arr.append(cdos.get_site_dos(i).densities) num += 1 else: arr2.append(cdos.get_site_dos(i).densities) num2 += 1 dos = Dos(cdos.efermi, cdos.energies, six.moves.reduce(add_densities, arr)) dos2 = Dos(cdos.efermi, cdos.energies, six.moves.reduce(add_densities, arr2)) dos.densities = {k: np.array(d / num) for k, d in dos.densities.items()} dos2.densities = {k: np.array(d / num2) for k, d in dos2.densities.items()} dsp = DosPlotter() dsp.add_dos('core', dos2) write_dos(dos, filename='core.dat') write_dos(dos2, filename='shell.dat') dsp.show()
def from_path(cls, path): vasprun_loc = zpath('{}/vasprun.xml'.format(path)) vasprun = Vasprun(vasprun_loc) return cls.from_vasprun(vasprun)
def get_dos(vasprun_dos): ## get CompleteDos object and "save" in hidden div in json format dos = Vasprun(vasprun_dos).complete_dos return json.dumps(dos.as_dict())
#!/usr/bin python # -*- encoding: utf-8 -*- ''' @Author : Celeste Young @File : 能带图.py @Time : 2020/12/30 13:42 @Tips : ''' import matplotlib.pyplot as plt from pymatgen.io.vasp.outputs import Vasprun from pymatgen.electronic_structure.plotter import BSDOSPlotter, BSPlotter, BSPlotterProjected, DosPlotter bs_vasprun = Vasprun("vasprun.xml", parse_projected_eigen=True) bs_data = bs_vasprun.get_band_structure(line_mode=True) dos_data = bs_vasprun.complete_dos banddos_fig = BSDOSPlotter(bs_projection=None, \ dos_projection=None, vb_energy_range=-5, \ fixed_cb_energy=5) band_fig = BSPlotter(bs=bs_data) band_fig.get_plot() plt.ylim(-2, 1)
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()) if cp_key_num != (len(self.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
def plot(args): plt = None if args.band or args.bandcheck: bsp = BSPlotting(vasprun='vasprun.xml', kpoints='KPOINTS' ) #line the path of vasprun.xml using the argument if args.bandcheck: bsp.printinform() elif args.band: para = _load_yaml("B") plt = bsp.get_plot(figsize=para["fig_size"], zero_to_efermi=para["zero_to_efermi"], fontsize=para["fontsize"], spindownoff=True, color=para["color"], ylim=para["ylim"], vbm_cbm_marker=para["vbm_cbm_marker"]) elif args.dos or args.partial: para = _load_yaml("D") if args.dos: f = open(args.name, "r") filelist = f.readlines()[1:] dp = DOSPlotting(vasprun='vasprun.xml', dos=filelist, zero_to_efermi=para["zero_to_efermi"], stack=para["stack"]) plt = dp.get_plot(figsize=para["fig_size"], xlim=para["xlim"], ylim=para["ylim"], fontsize=para["font_size"], color=para["color"]) plt.legend(frameon=False) if args.partial: if args.name: filelist = [] ylim = [] color = palettable.colorbrewer.qualitative.Set1_9.mpl_colors for e, i in enumerate(args.name): f = open(i, "r") filelist = f.readlines()[1:] dp = DOSPlotting(vasprun='vasprun.xml', dos=filelist, zero_to_efermi=para["zero_to_efermi"], stack=para["stack"]) plt = dp.get_plot(figsize=para["fig_size"], xlim=para["xlim"], ylim=para["ylim"], fontsize=para["font_size"], color=color[e % 9], label=i.split(".")[0]) ax = plt.gca() ylim.append(ax.get_ylim()[-1]) ax.set_ylim(0, max(ylim)) plt.legend(fontsize=para["font_size"] / 2, loc="upper right", frameon=False) else: print("Please use the -n argument") sys.exit(0) filelist = f.readlines()[1:] elif args.bdos: run = Vasprun('vasprun.xml', parse_dos=True) dos = run.complete_dos vrun = BSVasprun('vasprun.xml', parse_projected_eigen=True) bs = vrun.get_band_structure('KPOINTS', efermi=dos.efermi) bdpara = _load_yaml("BD") bsdosplot = BSDOSPlotter(bs_projection=bdpara['bs_projection'], dos_projection=bdpara['dos_projection'], vb_energy_range=bdpara['vb_energy_range'], cb_energy_range=bdpara['cb_energy_range'], fixed_cb_energy=bdpara['fixed_cb_energy'], egrid_interval=bdpara['egrid_interval'], font=bdpara['font'], axis_fontsize=bdpara['axis_fontsize'], tick_fontsize=bdpara['tick_fontsize'], legend_fontsize=bdpara['legend_fontsize'], bs_legend=bdpara['bs_legend'], dos_legend=bdpara['dos_legend'], rgb_legend=bdpara['rgb_legend'], fig_size=bdpara['fig_size']) plt = bsdosplot.get_plot(bs, dos=dos) if plt: if args.out_file: plt.savefig("%s.%s" % (args.out_file, args.format)) else: plt.show()
def dos_graph(rawdatadir, savedir, total_dos=True, by_element=False, by_orbital=False): dosrun = Vasprun("{}/vasprun.xml".format(rawdatadir), parse_dos=True) dos = dosrun.complete_dos # Get basic plot dos_graph.e_fermi = float(dosrun.efermi) dos_graph.band_gap = float(dosrun.eigenvalue_band_properties[0]) dosplot = DosPlotter() #dosplot = DosPlotter(sigma=0.1) if total_dos == True: dosplot.add_dos("Total DOS", dos) if by_element == True: dosplot.add_dos_dict(dos.get_element_dos()) if by_orbital == True: dosplot.add_dos_dict(dos.get_spd_dos()) plt = dosplot.get_plot(xlim=[-3, 3], ylim=[-15, 15], element_colors=True) plt.grid() plt.savefig("{}/DOSGraph".format(savedir)) plt.close() # Get plot for comparison with SOC total DOS plot dosplot = DosPlotter() dosplot.add_dos("Total DOS without SOC", dos) dosplot.add_dos_dict(dos.get_element_dos()) plt = dosplot.get_plot_total(xlim=[-3, 3], element_colors=True) plt.grid() plt.savefig("{}/DOSGraph_tot_DOS by Element without SOC".format(savedir)) plt.close() dosplot = DosPlotter() 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 } dosplot.add_dos("Total DOS without SOC", dos) dosplot.add_dos_dict(dos.get_orbital_dos()) plt = dosplot.get_plot_total(xlim=[-3, 3]) plt.grid() plt.savefig("{}/DOSGraph_tot_DOS by Orbital without SOC".format(savedir)) plt.close() """ # Get quick info about band gap (source: EIGENVAL) eigenval = Eigenval("{}/EIGENVAL".format(rawdatadir)) dos_graph.band_properties = eigenval.eigenvalue_band_properties """ # Get detailed info about band gap and CB/VB in each spin channel # (source: vasprun.xml) dos_graph.majority_vbm = \ dosrun.tdos.get_cbm_vbm_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.up)[1] dos_graph.majority_cbm = \ dosrun.tdos.get_cbm_vbm_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.up)[0] dos_graph.minority_vbm = \ dosrun.tdos.get_cbm_vbm_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.down)[1] dos_graph.minority_cbm = \ dosrun.tdos.get_cbm_vbm_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.down)[0] dos_graph.majority_gap = \ dosrun.tdos.get_gap_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.up) dos_graph.minority_gap = \ dosrun.tdos.get_gap_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=Spin.down) dos_graph.electronic_gap = \ dosrun.tdos.get_gap_alt(xlim=[-3,3],e_fermi=dos_graph.e_fermi, tol=0.3,abs_tol=True,spin=None) return
# feel free to self specify/remove if you're f*****g # around with testing/fixing data = [] # Premake the lofl # Iterator / / / standard stuff really for subdir, dirs, files in os.walk(workdir): for file in files: if file.endswith('OUTCAR'): try: print(subdir.replace(workdir, '')) # load OUTCAR file_ou = Outcar(subdir + '/OUTCAR') # load POSCAR file_POS = Structure.from_file(subdir + '/POSCAR') # load vasprun - not sure if this is even working tbh. 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_ou.final_energy, file_ou.final_energy / file_POS.composition.num_atoms, file_vr.converged ]) except: # ignore this painful except catcher - was testing on mostly malformed XMLs and this seemed ideal data.append([ subdir.replace(workdir, ''), file_POS.composition, file_POS.composition.num_atoms, file_ou.final_energy, file_ou.final_energy / file_POS.composition.num_atoms, '!!!', 'FLAG RAISED' ])
from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.entries.computed_entries import ( CompositionEnergyAdjustment, ComputedEntry, ComputedStructureEntry, ConstantEnergyAdjustment, EnergyAdjustment, GibbsComputedStructureEntry, ManualEnergyAdjustment, TemperatureEnergyAdjustment, ) from pymatgen.io.vasp.outputs import Vasprun from pymatgen.util.testing import PymatgenTest filepath = os.path.join(PymatgenTest.TEST_FILES_DIR, "vasprun.xml") vasprun = Vasprun(filepath) def test_energyadjustment(): ea = EnergyAdjustment(10) assert ea.name == "Manual adjustment" assert ea.cls == {} ead = ea.as_dict() ea2 = EnergyAdjustment.from_dict(ead) assert str(ead) == str(ea2.as_dict()) def test_manual_energy_adjustment(): ea = ManualEnergyAdjustment(10) assert ea.name == "Manual energy adjustment" assert ea.value == 10
def plot_gamma_surface(fmt='pdf'): """ Collect the energies from a grid of static energy calculations to plot the Gamma surface between two layers of the 2D material. Args: fmt (str): matplotlib format style. Check the matplotlib docs for options. """ os.chdir('friction/lateral') static_dirs = [ d.split('x') for d in os.listdir(os.getcwd()) if 'x' in d and len(d) == 3 ] n_divs_x = max([int(d[0]) for d in static_dirs]) n_divs_y = max([int(d[1]) for d in static_dirs]) lattice = Structure.from_file('POSCAR').lattice area = np.cross(lattice._matrix[0], lattice._matrix[1])[2] ax = plt.figure(figsize=(n_divs_x * 1.2, n_divs_y * 1.2)).gca() ax.set_xlim(0, n_divs_x + 1) ax.set_ylim(0, n_divs_y + 1) energies = [] x_values = range(n_divs_x + 1) y_values = range(n_divs_y + 1) not_converged = [] for x in x_values: energies.append([]) for y in y_values: dir = '{}x{}'.format(x, y) os.chdir(dir) try: energy = Vasprun('vasprun.xml').final_energy / area energies[x].append(energy) except: not_converged.append('{}x{}'.format(x, y)) energies[x].append(0) os.chdir('../') energies[x].append(energies[x][0]) energies.append([]) # ENERGY_ARRAY[n_divs_x] = ENERGY_ARRAY[0] if not_converged: warnings.warn('{} did not converge.'.format(not_converged)) for coords in not_converged: energies[int(coords.split('x')[0])][int( coords.split('x')[1])] = energy minima = [] maxima = [] for x in x_values: minima.append(min(energies[x])) maxima.append(max(energies[x])) abs_minimum = min(minima) abs_maximum = max(maxima) for x in range(n_divs_x + 1): for y in range(n_divs_y + 1): # Plot all energies relative to the global minimum. scaled_energy = energies[x][y] - abs_minimum if '{}x{}'.format(x, y) in not_converged: color_code = 'w' else: color_code = plt.cm.jet(scaled_energy / (abs_maximum - abs_minimum)) ax.add_patch( plt.Rectangle((x, y), width=1, height=1, facecolor=color_code, linewidth=0)) # Get rid of annoying ticks. ax.axes.get_yaxis().set_ticks([]) ax.axes.get_xaxis().set_ticks([]) os.chdir('../../') plt.savefig('gamma_surface.{}'.format(fmt), transparent=True) plt.close()
subfold = os.path.basename(path) # finding charge state from subfolder name U_par = subfold.replace('U_', '') U = float(U_par) # build path of OUTCAR file path_vasprun = (dir + 'vasprun.xml') # reading vasprun.xml and CONTCAR with pymatgen contcar = Poscar.from_file(dir + "CONTCAR") structure = contcar.structure.as_dict() # getting lattice parameter lattice_par = structure['lattice']['a'] # reading VASP OUTPUT vasprun = Vasprun(path_vasprun) #getting energy gap (gap, cbm, vbm, is_direct) = vasprun.eigenvalue_band_properties # writing output file with charge state and total enery file_table.write('%f %f %f \n' % (U, lattice_par, gap)) file_table.close() print(f'Data printed in "{system_name}-a-Eg.dat"') print('') import matplotlib.pyplot as plt import numpy as np plt.figure(figsize=(18, 10))
def plot_friction_force(fmt='pdf'): """ Plot the sinusoidal curve of delta E between basin and saddle points for each normal spacing dz. Args: fmt (str): matplotlib format style. Check the matplotlib docs for options. """ n_surface_atoms = get_number_of_surface_atoms() os.chdir('friction/normal') f, (ax1, ax2) = plt.subplots(2, figsize=(16, 16)) spacings = sorted( [float(spc) for spc in os.listdir(os.getcwd()) if os.path.isdir(spc)]) spc_range = spacings[-1] - spacings[0] + 0.1 for spacing in spacings: os.chdir(str(spacing)) subdirectories = os.listdir(os.getcwd()) amplitude = abs( Vasprun('{}/vasprun.xml'.format(subdirectories[0])).final_energy - Vasprun('{}/vasprun.xml'.format(subdirectories[1])).final_energy ) / (2 * n_surface_atoms) start_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[0])).sites[-1].coords end_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[1])).sites[-1].coords dist = np.sqrt((start_coords[0] - end_coords[0])**2 + (start_coords[1] - end_coords[1])**2) b = (2 * np.pi) / (dist * 2) x = np.arange(0, 4, 0.01) sinx = [amplitude * np.sin(b * val) + amplitude for val in x] cosx = [ b * amplitude * np.cos(b * val) if np.cos(b * val) > 0 else 0 for val in x ] ax1.plot(x, sinx, linewidth=8, color=plt.cm.jet(-(spacing - 4) / spc_range), label=spacing) ax1.set_xticklabels(ax1.get_xticks(), family='serif', fontsize=18) ax1.set_yticklabels(ax1.get_yticks(), family='serif', fontsize=18) ax1.set_xlabel(r'$\mathrm{\Delta d\/(\AA)}$', family='serif', fontsize=24) ax1.set_ylabel(r'$\mathrm{E(z)\/(eV)}$', family='serif', fontsize=24) ax2.plot(x, cosx, linewidth=8, color=plt.cm.jet(-(spacing - 4) / spc_range), label=spacing) ax2.set_xticklabels(ax2.get_xticks(), family='serif', fontsize=18) ax2.set_yticklabels(ax2.get_yticks(), family='serif', fontsize=18) ax2.set_xlabel(r'$\mathrm{\Delta d\/(\AA)}$', family='serif', fontsize=24) ax2.set_ylabel(r'$\mathrm{F_f\/(eV/\AA)}$', family='serif', fontsize=24) os.chdir('../') ax1.legend(loc='upper right') ax2.legend(loc='upper right') os.chdir('../../') plt.savefig('F_f.{}'.format(fmt))
def run_task(self, fw_spec): get_rdf = self.get('get_rdf') or True get_diffusion = self.get('get_diffusion') or True get_viscosity = self.get('get_viscosity') or True get_vdos = self.get('get_vdos') or True get_run_data = self.get('get_run_data') or True time_step = self.get('time_step') or 2 checkpoint_dirs = fw_spec.get('checkpoint_dirs', False) calc_dir = get_calc_loc(True, fw_spec["calc_locs"])["path"] calc_loc = os.path.join(calc_dir, 'XDATCAR.gz') ionic_step_skip = self.get('ionic_step_skip') or 1 ionic_step_offset = self.get('ionic_step_offset') or 0 analysis_spec = self.get('analysis_spec') or {} if checkpoint_dirs: logger.info("LOGGER: Assimilating checkpoint structures") ionic_steps = [] structures = [] for d in checkpoint_dirs: ionic_steps.extend( Vasprun(os.path.join(d, "vasprun.xml.gz")).ionic_steps) structures.extend( Vasprun(os.path.join(d, 'vasprun.xml.gz'), ionic_step_skip=ionic_step_skip, ionic_step_offset=ionic_step_offset).structures) else: structures = Xdatcar(calc_loc).structures #write a trajectory file for Dospt molecules = [] for struc in structures: molecules.append( Molecule(species=struc.species, coords=[s.coords for s in struc.sites])) XYZ(mol=molecules).write_file('traj.xyz') db_dict = {} db_dict.update({'density': float(structures[0].density)}) db_dict.update(structures[0].composition.to_data_dict) db_dict.update({'checkpoint_dirs': checkpoint_dirs}) if get_rdf: logger.info("LOGGER: Calculating radial distribution functions...") rdf = RadialDistributionFunction(structures=structures) rdf_dat = rdf.get_radial_distribution_functions(nproc=4) db_dict.update({'rdf': rdf.get_rdf_db_dict()}) del rdf del rdf_dat if get_vdos: logger.info("LOGGER: Calculating vibrational density of states...") vdos = VDOS(structures) vdos_dat = vdos.calc_vdos_spectrum(time_step=time_step * ionic_step_skip) vdos_diff = vdos.calc_diffusion_coefficient(time_step=time_step * ionic_step_skip) db_dict.update({'vdos': vdos_dat}) del vdos del vdos_dat if get_diffusion: logger.info("LOGGER: Calculating the diffusion coefficients...") diffusion = Diffusion(structures, t_step=time_step, l_lim=50, skip_first=250, block_l=1000, ci=0.95) D = {'msd': {}, 'vdos': {}} for s in structures[0].types_of_specie: D['msd'][s.symbol] = diffusion.getD(s.symbol) if vdos_diff: D['vdos'] = vdos_diff db_dict.update({'diffusion': D}) del D if get_viscosity: logger.info("LOGGER: Calculating the viscosity...") viscosities = [] if checkpoint_dirs: for dir in checkpoint_dirs: visc = Viscosity(dir).calc_viscosity() viscosities.append(visc['viscosity']) viscosity_dat = { 'viscosity': np.mean(viscosities), 'StdDev': np.std(viscosities) } db_dict.update({'viscosity': viscosity_dat}) del viscosity_dat if get_run_data: if checkpoint_dirs: logger.info("LOGGER: Assimilating run stats...") data = MD_Data() for directory in checkpoint_dirs: data.parse_md_data(directory) md_stats = data.get_md_stats() else: logger.info("LOGGER: Getting run stats...") data = MD_Data() data.parse_md_data(calc_dir) md_stats = data.get_md_stats() db_dict.update({'md_data': md_stats}) if analysis_spec: logger.info("LOGGER: Adding user-specified data...") db_dict.update(analysis_spec) logger.info("LOGGER: Pushing data to database collection...") db_file = env_chk(">>db_file<<", fw_spec) db = VaspCalcDb.from_db_file(db_file, admin=True) db.collection = db.db["md_data"] db.collection.insert_one(db_dict) return FWAction()
def plot_normal_force(basin_dir, fmt='pdf'): """ Plot the LJ-like curve of the energy at the basin point as a function of normal spacing dz. Args: basin_dir (str): directory corresponding to the minimum energy on the gamma surface. Generally obtained by the get_basin_and_peak_locations() function. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ n_surface_atoms = get_number_of_surface_atoms() os.chdir('friction/normal') spacings = [ float(dir) for dir in os.listdir(os.getcwd()) if os.path.isdir(dir) ] spacings.sort() fig = plt.figure(figsize=(16, 10)) ax = fig.gca() ax2 = ax.twinx() abs_E = [ Vasprun('{}/{}/vasprun.xml'.format(spacing, basin_dir)).final_energy / n_surface_atoms for spacing in spacings ] E = [energy - abs_E[-1] for energy in abs_E] spline = interpolate.splrep(spacings, E, s=0) xnew = np.arange(spacings[0], spacings[-1], 0.001) ynew = interpolate.splev(xnew, spline, der=0) ynew_slope = interpolate.splev(spacings, spline, der=1) ax.set_xlim(spacings[0], spacings[-1]) ax.plot([spacings[0], spacings[-1]], [0, 0], '--', color=plt.cm.jet(0)) ax2.plot([spacings[0], spacings[-1]], [0, 0], '--', color=plt.cm.jet(0.9)) E_z = ax.plot(xnew, ynew, color=plt.cm.jet(0), linewidth=4, label=r'$\mathrm{E(z)}$') F_N = ax2.plot(spacings, [-y for y in ynew_slope], color=plt.cm.jet(0.9), linewidth=4, label=r'$\mathrm{F_N}$') ax.set_ylim(ax.get_ylim()) ax.set_xticklabels(ax.get_xticks(), family='serif', fontsize=18) ax.set_yticklabels(ax.get_yticks(), family='serif', fontsize=18) ax2.set_yticklabels(ax2.get_yticks(), family='serif', fontsize=18) ax.set_xlabel(r'$\mathrm{z\/(\AA)}$', fontsize=24) ax.set_ylabel(r'$\mathrm{E(z)\/(eV)}$', fontsize=24) ax2.set_ylabel(r'$\mathrm{F_N\/(eV/\AA)}$', fontsize=24) data = E_z + F_N labs = [l.get_label() for l in data] ax.legend(data, labs, loc='upper right', fontsize=24) ax.plot(spacings, E, linewidth=0, marker='o', color=plt.cm.jet(0), markersize=10, markeredgecolor='none') os.chdir('../../') plt.savefig('F_N.{}'.format(fmt))
def _get_vasprun(args): return Vasprun(args[0], ionic_skipstep=args[1], parse_dos=False, parse_eigen=False)
def plot_mu_vs_F_N(basin_dir, fmt='pdf'): """ Plot friction coefficient 'mu' vs. F_Normal. mu = F_friction / F_Normal. Args: basin_dir (str): directory corresponding to the minimum energy on the gamma surface. Generally obtained by the get_basin_and_peak_locations() function. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ n_surface_atoms = get_number_of_surface_atoms() fig = plt.figure(figsize=(16, 10)) # ax = fig.gca() # ax2 = ax.twinx() os.chdir('friction/normal') spacings = [ float(dir) for dir in os.listdir(os.getcwd()) if os.path.isdir(dir) ] spacings.sort() abs_E = [ Vasprun('{}/{}/vasprun.xml'.format(spacing, basin_dir)).final_energy / n_surface_atoms for spacing in spacings ] E = [energy - abs_E[-1] for energy in abs_E] spline = interpolate.splrep(spacings, E, s=0) # xnew = np.arange(spacings[0], spacings[-1], 0.001) # ynew = interpolate.splev(xnew, spline, der=0) ynew_slope = interpolate.splev(spacings, spline, der=1) F_N = [-y * 1.602 for y in ynew_slope] F_f = [] sorted_dirs = sorted( [float(spc) for spc in os.listdir(os.getcwd()) if os.path.isdir(spc)]) for spacing in sorted_dirs: os.chdir(str(spacing)) subdirectories = os.listdir(os.getcwd()) amplitude = abs( Vasprun('{}/vasprun.xml'.format(subdirectories[0])).final_energy - Vasprun('{}/vasprun.xml'.format(subdirectories[1])).final_energy ) / (2 * n_surface_atoms) start_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[0])).sites[-1].coords end_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[1])).sites[-1].coords dist = np.sqrt((start_coords[0] - end_coords[0])**2 + (start_coords[1] - end_coords[1])**2) b = (2 * np.pi) / (dist * 2) x = np.arange(0, 4, 0.01) # sinx = [amplitude * np.sin(b * val) + amplitude for val in x] cosx = [ b * amplitude * np.cos(b * val) if np.cos(b * val) > 0 else 0 for val in x ] F_f.append(max(cosx) * 1.602) os.chdir('../') os.chdir('../../') mu = [f / N for f, N in zip(F_f, F_N)] ax = plt.figure().gca() ax.plot(F_N, mu, linewidth=2, marker='o', markeredgecolor='none', markersize=3, color=plt.cm.jet(0)) plt.savefig('mu_vs_F_N.{}'.format(fmt))
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_mu_vs_F_N(basin_dir): """ Essentially the same function as plotting, but without the plot. Args: basin_dir (str): directory corresponding to the minimum energy on the gamma surface. Generally obtained by the get_basin_and_peak_locations() function. Returns: dic: Of the form {'F_N': F_N, 'mu': mu, 'F_f': F_f}, where forces are in nN. """ n_surface_atoms = get_number_of_surface_atoms() os.chdir('friction/normal') spacings = [ float(dir) for dir in os.listdir(os.getcwd()) if os.path.isdir(dir) ] spacings.sort() abs_E = [ Vasprun('{}/{}/vasprun.xml'.format(spacing, basin_dir)).final_energy / n_surface_atoms for spacing in spacings ] E = [energy - abs_E[-1] for energy in abs_E] spline = interpolate.splrep(spacings, E, s=0) xnew = np.arange(spacings[0], spacings[-1], 0.001) ynew = interpolate.splev(xnew, spline, der=0) ynew_slope = interpolate.splev(spacings, spline, der=1) # Convert eV.A to nN F_N = [-y * 1.602 for y in ynew_slope] F_f = [] for spacing in sorted( [float(spc) for spc in os.listdir(os.getcwd()) if os.path.isdir(spc)]): os.chdir(str(spacing)) subdirectories = os.listdir(os.getcwd()) try: amplitude = abs( Vasprun('{}/vasprun.xml'.format(subdirectories[0])). final_energy - Vasprun('{}/vasprun.xml'.format( subdirectories[1])).final_energy) / (2 * n_surface_atoms) except: print( 'One or more jobs in {}/ have not converged.'.format(spacing)) start_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[0])).sites[-1].coords end_coords = Structure.from_file('{}/POSCAR'.format( subdirectories[1])).sites[-1].coords dist = np.sqrt((start_coords[0] - end_coords[0])**2 + (start_coords[1] - end_coords[1])**2) b = (2 * np.pi) / (dist * 2) x = np.arange(0, 4, 0.01) # sinx = [amplitude * np.sin(b * val) + amplitude for val in x] cosx = [ b * amplitude * np.cos(b * val) if np.cos(b * val) > 0 else 0 for val in x ] F_f.append(max(cosx) * 1.602) os.chdir('../') os.chdir('../../') mu = [f / N for f, N in zip(F_f, F_N)] return {'F_N': F_N, 'mu': mu, 'F_f': F_f}
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[(1, 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)
About their differences: The two methods define differently what is the band gap. The eigenvalue_band_properties looks at occupations. Here there are partial occupations of your upper bands. Therefore this depends on the smearing you use. The Bandstructure.get_band_gap() looks at bands above and below fermi level. Here there are bands crossing the fermi level. So the method considers it as a metal and gives you a zero band gap. (see ref: https://github.com/materialsproject/pymatgen/issues/455) In general, get_band_structure works better. """ """ In addition to the two methods in pymatgen, here, I also provide third method in which band gap was calculated from DOSCAR to have a cross-check. """ # Method 1 and 2 by using pymatgen parse_vasprun = Vasprun('vasprun.xml') print(parse_vasprun) (gap, cbm, vbm, is_direct) = parse_vasprun.eigenvalue_band_properties print('pymatgen, eigenvalue_band_properties') print('gap,', "cbm,", "vbm,", "is_direct") print(gap, cbm, vbm, is_direct) print('\t') print('pymatgen, get_band_structure') bs = parse_vasprun.get_band_structure() gap = bs.get_band_gap() print(gap['energy']) # Method 3 by calculating band gap from DOSCAR """ This was inspired by Jeffw Doak https://github.com/jeffwdoak/vasp_scripts/blob/master/vasp_scripts/bandgap.py
def vac_antisite_def_parse_energy(mpid, mapi_key=None): if not mpid: print("============\nERROR: Provide an mpid\n============") return if not mapi_key: with MPRester() as mp: structure = mp.get_structure_by_material_id(mpid) else: with MPRester(mapi_key) as mp: structure = mp.get_structure_by_material_id(mpid) energy_dict = {} antisites = [] vacancies = [] def_folders = glob.glob(os.path.join(mpid, "vacancy*")) def_folders += glob.glob(os.path.join(mpid, "antisite*")) def_folders += glob.glob(os.path.join(mpid, "bulk")) for defdir in def_folders: fldr_name = os.path.split(defdir)[1] vr_file = os.path.join(defdir, 'vasprun.xml') if not os.path.exists(vr_file): print (fldr_name, ": vasprun.xml doesn't exist in the folder. " \ "Abandoning parsing of energies for {}".format(mpid)) break # Further processing for the mpid is not useful try: vr = Vasprun(vr_file) except: print( fldr_name, ":Failure, couldn't parse vaprun.xml file. " "Abandoning parsing of energies for {}".format(mpid)) break if not vr.converged: print( fldr_name, ": Vasp calculation not converged. " "Abandoning parsing of energies for {}".format(mpid)) break # Further processing for the mpid is not useful fldr_fields = fldr_name.split("_") if 'bulk' in fldr_fields: bulk_energy = vr.final_energy bulk_sites = vr.structures[-1].num_sites elif 'vacancy' in fldr_fields: site_index = int(fldr_fields[1]) site_multiplicity = int(fldr_fields[2].split("-")[1]) site_specie = fldr_fields[3].split("-")[1] energy = vr.final_energy vacancies.append({ 'site_index': site_index, 'site_specie': site_specie, 'energy': energy, 'site_multiplicity': site_multiplicity }) elif 'antisite' in fldr_fields: site_index = int(fldr_fields[1]) site_multiplicity = int(fldr_fields[2].split("-")[1]) site_specie = fldr_fields[3].split("-")[1] substitution_specie = fldr_fields[4].split("-")[1] energy = vr.final_energy antisites.append({ 'site_index': site_index, 'site_specie': site_specie, 'energy': energy, 'substitution_specie': substitution_specie, 'site_multiplicity': site_multiplicity }) else: print("All calculations successful for {}".format(mpid)) e0 = bulk_energy / bulk_sites * structure.num_sites for vac in vacancies: vac_flip_energy = vac['energy'] - bulk_energy vac['energy'] = vac_flip_energy vacancies.sort(key=lambda entry: entry['site_index']) for antisite in antisites: as_flip_energy = antisite['energy'] - bulk_energy antisite['energy'] = as_flip_energy antisites.sort(key=lambda entry: entry['site_index']) energy_dict[mpid] = { 'structure': structure, 'e0': e0, 'vacancies': vacancies, 'antisites': antisites } return energy_dict return {} # Return Null dict due to failure
def parse_md_data(self, input): """ Parses the md run data from a directory. Args: input: directory for the md run containing a vasprun.xml and OSZICAR file Returns: None """ if os.path.isfile(os.path.join(input, 'vasprun.xml.gz')): v = Vasprun(os.path.join(input, 'vasprun.xml.gz')) elif os.path.isfile(os.path.join(input, 'vasprun.xml')): v = Vasprun(os.path.join(input, 'vasprun.xml')) else: raise FileNotFoundError if os.path.isfile(os.path.join(input, 'OSZICAR.gz')): o = Oszicar(os.path.join(input, 'OSZICAR.gz')) elif os.path.isfile(os.path.join(input, 'OSZICAR')): o = Oszicar(os.path.join(input, 'OSZICAR')) else: raise FileNotFoundError self.composition = v.structures[0].composition self.volume = v.structures[0].volume nsteps = v.nionic_steps self.nsteps += nsteps if self.time: starttime = self.time[-1] self.time.extend( np.add( np.arange(0, nsteps) * v.parameters['POTIM'], starttime)) else: self.time.extend(np.arange(0, nsteps) * v.parameters['POTIM']) pressure = [] etot = [] ekin = [] temp = [] for i, step in enumerate(o.ionic_steps): temp.append(step['T']) for i, step in enumerate(v.ionic_steps): ekin.append(step['kinetic']) etot.append(step['total']) stress = step['stress'] kinP = (2 / 3) * ekin[i] pressure.append((1 / 3) * np.trace(stress) + kinP) self.md_data['pressure'].extend(pressure) self.md_data['etot'].extend(etot) self.md_data['ekin'].extend(ekin) self.md_data['temp'].extend(temp) self.md_acfs['pressure'] = autocorrelation(self.md_data['pressure'], normalize=True) self.md_acfs['pressure'] = autocorrelation(self.md_data['pressure'], normalize=True) self.md_acfs['pressure'] = autocorrelation(self.md_data['pressure'], normalize=True) self.md_acfs['pressure'] = autocorrelation(self.md_data['pressure'], normalize=True)
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 _mp_helper_energy(parse_vacuum, get_core, hkl, path, slab_thickness, vac_thickness, slab_index, core_atom=None, bulk_nn=None, **kwargs): """ Helper function for multiprocessing, returns a list of lists of the main extracted data, electrostatic potential and core energies Same args as for parse_fols, only that path is the path to the folder in which the vasprun and OUTCAR for the specific slab/vacuum/index slab are. """ df_list, electrostatic_list, core_energy_list, gradient_list = ( [] for i in range(4)) # instantiate structure, slab, vasprun and outcar objects vsp_path = '{}/vasprun.xml'.format(path) otc_path = '{}/OUTCAR'.format(path) vsp = Vasprun(vsp_path, parse_potcar_file=False) otc = Outcar(otc_path) slab = slab_from_file(vsp.final_structure, hkl) vsp_dict = vsp.as_dict() # extract the time data otc_times = otc.run_stats df_list.append({ 'hkl_string': ''.join(map(str, hkl)), 'hkl_tuple': hkl, 'slab_thickness': slab_thickness, 'vac_thickness': vac_thickness, 'slab_index': slab_index, 'atoms': vsp_dict['nsites'], 'area': slab.surface_area, 'bandgap': vsp_dict['output']['bandgap'], 'slab_energy': vsp_dict['output']['final_energy'], 'slab_per_atom': vsp_dict['output']['final_energy_per_atom'], 'time_taken': otc_times['Elapsed time (sec)'] }) if parse_vacuum: electrostatic_list.append(vacuum(path)) lpt = '{}/LOCPOT'.format(path) p = electrostatic_potential(lpt, save_plt=False, save_csv=False) # gradient in eV g = p['gradient'].to_numpy() ratio = int(vac_thickness) / (int(vac_thickness) + int(slab_thickness)) # check if slab is centred so can get the gradient if 0.45 < slab.center_of_mass[2] < 0.55: # divide by 2 bc two regions, 0.75 is a scaling factor that # should hopefully work to avoid any charge from dangling # bonds? a = int(len(g) * ratio / 2 * 0.75) gradient_list.append(np.mean(g[:a]) * 1000) else: a = int(len(g) * ratio * 0.75) # if atoms are more towards the end of the slab, the start # should be vacuum if slab.center_of_mass[2] > 0.5: gradient_list.append(np.mean(g[:a]) * 1000) # and then if atoms are at the start, the vacuum is at # the end else: gradient_list.append(np.mean(g[(len(g) - a):]) * 1000) if get_core: core_energy_list.append( core_energy(core_atom, bulk_nn, outcar=otc_path, structure=slab, **kwargs)) return [df_list, electrostatic_list, core_energy_list, gradient_list]