def __init__(self, label, LOC): self.label = label self.LOC = LOC E, V = [], [] alldos = [] # get all the data from the atoms. E, V and DOS for calculator in LOC: with calculator as calc: atoms = calc.get_atoms() E.append(atoms.get_potential_energy()) V.append(atoms.get_volume()) dos = DOS(calc, width=0.2) n = dos.get_dos() e = dos.get_energies() alldos.append((e, n)) E = np.array(E) V = np.array(V) self.E = E self.V = V self.alldos = alldos # this is the range we fit over self.T = np.linspace(400, 1500, 20)
def get_dos(prefix, outdir=None, schema=None, width=0.01, npts=100): """ This function returns an DOS object from an output xml Espresso file containing the results of a DOS calculation. :param prefix: prefix of saved output files :param outdir: directory containing the input data. Default to the value of \ ESPRESSO_TMPDIR environment variable if set or current directory ('.') otherwise :param schema: the XML schema to be used to read and validate the XML output file :param width: width of the gaussian to be used for the DOS (in eV) :param npts: number of points of the DOS :return: a DOS object """ label = get_label(prefix, outdir) # set a simple calculator, only to read the xml file results calcul = PostqeCalculator(atoms=None, label=label, schema=schema) # define the Atoms structure reading the xml file atoms = get_atoms_from_xml_output(calcul.label + ".xml", schema=schema) atoms.set_calculator(calcul) # read the results atoms.calc.read_results() # Create a DOS object with width= eV and npts points dos = DOS(calcul, width=width, npts=npts) return dos
import matplotlib.pyplot as plt import numpy as np from ase.dft import DOS import pylab as plt a = 3.9 # approximate lattice constant b = a / 2. bulk = Atoms([Atom('Pd', (0.0, 0.0, 0.0))], cell=[(0, b, b), (b, 0, b), (b, b, 0)]) kpts = [8, 10, 12, 14, 16, 18, 20] calcs = [Vasp('bulk/pd-dos-k{0}-ismear-5'.format(k), encut=300, xc='PBE', kpts=[k, k, k], atoms=bulk) for k in kpts] Vasp.wait(abort=True) for calc in calcs: # this runs the calculation if calc.potential_energy is not None: dos = DOS(calc, width=0.2) d = dos.get_dos() + k / 4.0 e = dos.get_energies() plt.plot(e, d, label='k={0}'.format(k)) else: pass plt.xlabel('energy (eV)') plt.ylabel('DOS') plt.legend() plt.savefig('images/pd-dos-k-convergence-ismear-5.png') plt.show()
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. See :func:`jasp_kpts.write_kpoints`. >>> from jasp import * >>> from jasp.jasp_bandstructure import * >>> with jasp('bulk/tio2/step3') as calc: ... n, bands, p = calc.get_bandstructure(kpts_path=[('$\Gamma$',[0.0, 0.0, 0.0]), ('X',[0.5, 0.5, 0.0]), ('X',[0.5, 0.5, 0.0]), ('M',[0.0, 0.5, 0.5]), ('M',[0.0, 0.5, 0.5]), ('$\Gamma$',[0.0, 0.0, 0.0])]) >>> p.savefig('images/tio2-bandstructure-dos.png') returns (npoints, band_energies, fighandle) """ kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory cwd = os.getcwd() base, end = os.path.split(cwd) wd = cwd + '/bandstructure' self.clone(wd) with jasp(wd, kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, debug=logging.DEBUG, icharg=11) as calc: calc.calculate() fig = plt.figure() with open('EIGENVAL') as f: line1 = f.readline() line2 = f.readline() line3 = f.readline() line4 = f.readline() comment = f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] blankline = f.readline() band_energies = [[] for i in range(nbands)] for i in range(npoints): x, y, z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id-1].append(energy) blankline = f.readline() f.close() ax1 = plt.subplot(121) for i in range(nbands): plt.plot(range(npoints), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels)/2 + 1 ax.set_xticks(np.linspace(0, npoints, nticks)) L = [] L.append(labels[0]) for i in range(2, len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0, c='r') plt.subplot(122, sharey=ax1) plt.plot(d, e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) plt.show() return (npoints, band_energies, fig)
from ase.lattice.cubic import FaceCenteredCubic from ase.dft import DOS atoms = FaceCenteredCubic(directions=[[0,1,1], [1,0,1], [1,1,0]], size=(1,1,1), symbol='Ni') atoms[0].magmom = 1 with jasp('bulk/Ni-PBE', ismear=-5, kpts=(5,5,5), xc='PBE', ispin=2,lorbit=11, atoms=atoms) as calc: print 'PBE energy: ',atoms.get_potential_energy() dos = DOS(calc, width=0.2) e_pbe = dos.get_energies() d_pbe = dos.get_dos() calc.clone('bulk/Ni-PBE0') calc.clone('bulk/Ni-HSE06') with jasp('bulk/Ni-PBE0') as calc: calc.set(lhfcalc=True, algo='D', time=0.4) atoms = calc.get_atoms() print 'PBE0 energy: ',atoms.get_potential_energy() dos = DOS(calc, width=0.2) e_pbe0 = dos.get_energies() d_pbe0 = dos.get_dos() with jasp('bulk/Ni-HSE06') as calc: calc.set(lhfcalc=True,
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. See :func:`jasp_kpts.write_kpoints`. >>> from jasp import * >>> from jasp.jasp_bandstructure import * >>> with jasp('bulk/tio2/step3') as calc: ... n, bands, p = calc.get_bandstructure(kpts_path=[('$\Gamma$',[0.0, 0.0, 0.0]), ('X',[0.5, 0.5, 0.0]), ('X',[0.5, 0.5, 0.0]), ('M',[0.0, 0.5, 0.5]), ('M',[0.0, 0.5, 0.5]), ('$\Gamma$',[0.0, 0.0, 0.0])]) >>> p.savefig('images/tio2-bandstructure-dos.png') returns (npoints, band_energies, fighandle) """ kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory cwd = os.getcwd() base, end = os.path.split(cwd) wd = cwd + '/bandstructure' self.clone(wd) with jasp( wd, kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, debug=logging.DEBUG, icharg=11) as calc: calc.calculate() fig = plt.figure() with open('EIGENVAL') as f: line1 = f.readline() line2 = f.readline() line3 = f.readline() line4 = f.readline() comment = f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] blankline = f.readline() band_energies = [[] for i in range(nbands)] for i in range(npoints): x, y, z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id - 1].append(energy) blankline = f.readline() f.close() ax1 = plt.subplot(121) for i in range(nbands): plt.plot(range(npoints), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels) / 2 + 1 ax.set_xticks(np.linspace(0, npoints, nticks)) L = [] L.append(labels[0]) for i in range(2, len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0, c='r') plt.subplot(122, sharey=ax1) plt.plot(d, e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) plt.show() return (npoints, band_energies, fig)
p = atoms.get_potential_energy() save(result_file, '4th calculation \n total energy : {0} eV, {1} eV/atom'.format(p, p/len(atoms))) tm = atoms.get_magnetic_moment() m = atoms.get_magnetic_moments() save(result_file, 'total magnetic moment : {0} mB {1} mB/atom '.format(tm, tm/len(atoms))) save(result_file, 'magnetic moment: {0}'.format(m)) vdos = VaspDos() vdos.read_doscar('DOSCAR') print vdos.efermi print vdos.site_dos(0,0) dos = DOS(calc, width=0.05) d = dos.get_dos() up = dos.get_dos(0) down = dos.get_dos(1) e = dos.get_energies() plt.plot(e,d, label='total') plt.plot(e,up, label='spin-up') plt.plot(e,-1.0*down, label='spin-down') plt.grid(True) plt.xlim(-20, 20) plt.ylim(-10, 10) plt.legend()
from vasp import Vasp from ase.dft import DOS # This seems very slow... calc = Vasp('bulk/pd-dos-k20-ismear-5') print DOS(calc, width=0.2)
import matplotlib.pyplot as plt import numpy as np from ase.dft import DOS import pylab as plt a = 3.9 # approximate lattice constant b = a / 2. bulk = Atoms([Atom('Pd', (0.0, 0.0, 0.0))], cell=[(0, b, b), (b, 0, b), (b, b, 0)]) kpts = [8, 10, 12, 14, 16, 18, 20] calcs = [ Vasp('bulk/pd-dos-k{0}-ismear-5'.format(k), encut=300, xc='PBE', kpts=[k, k, k], atoms=bulk) for k in kpts ] Vasp.wait(abort=True) for calc in calcs: # this runs the calculation if calc.potential_energy is not None: dos = DOS(calc, width=0.2) d = dos.get_dos() + k / 4.0 e = dos.get_energies() plt.plot(e, d, label='k={0}'.format(k)) else: pass plt.xlabel('energy (eV)') plt.ylabel('DOS') plt.legend() plt.savefig('images/pd-dos-k-convergence-ismear-5.png') plt.show()
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10, show=False): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. returns (npoints, band_energies, fighandle) """ self.update() self.stop_if(self.potential_energy is None) kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory wd = os.path.join(self.directory, 'bandstructure') self.clone(wd) calc = vasp.Vasp(wd) calc.set(kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, icharg=11) calc.update() if calc.potential_energy is None: return None, None, None fig = plt.figure() with open(os.path.join(wd, 'EIGENVAL')) as f: # skip 5 lines f.readline() f.readline() f.readline() f.readline() f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] f.readline() # skip line band_energies = [[] for i in range(nbands)] for i in range(npoints): x, y, z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id - 1].append(energy) f.readline() # skip line ax1 = plt.subplot(121) for i in range(nbands): plt.plot(range(npoints), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels) / 2 + 1 ax.set_xticks(np.linspace(0, npoints, nticks)) L = [] L.append(labels[0]) for i in range(2, len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0, c='r') plt.subplot(122, sharey=ax1) plt.plot(d, e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) if show: plt.show() return (npoints, band_energies, fig)
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10, show=False, ylim=None, outdir=None, outfile=None): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. returns (npoints, band_energies, fighandle, Energy gap, Convection band minimum, valance band maximum) """ prevdir = os.getcwd() #store for later use self.update() self.stop_if(self.potential_energy is None) kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory wd = os.path.join(self.directory, 'bandstructure') if not os.path.exists(wd): self.clone(wd) calc = Vasp(wd) calc.set( kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, icharg=11) calc.update() if calc.potential_energy is None: return None, None, None, None, None, None else: # I don't think this will work unless the calculation is complete! archiveKpts = os.path.join(wd, 'KPOINTS_old') originalKpts = os.path.join(wd, 'KPOINTS') if not os.path.exists( archiveKpts): # archive the original KPOINTS file shutil.copy(originalKpts, archiveKpts) with open(archiveKpts, 'r') as kpts_infile: # get lines of old KPOINTS KPtsLines = kpts_infile.readlines() # Append labels for high-symmetry points to lines of the KPOINTS file reject_chars = '$' for idx, label in enumerate(labels): newlabel = label for ch in reject_chars: newlabel = newlabel.replace(ch, '') KPtsLines[4 + idx] = KPtsLines[4 + idx][:-1] + f' ! {newlabel}\n' # Write a new version of the k-points file with open(originalKpts, 'w') as kpts_outfile: for line in KPtsLines: kpts_outfile.write(line) EIGFILE = os.path.join(wd, 'EIGENVAL') npoints, band_energies, fig = makeBandPlot( EIGFILE, labels, ef=ef, ylim=ylim, d=d, e=e, # DOS data show=show) # Run sumo-bandplot, if it exists check_sumo = sp.run(['which', 'sumo-bandplot'], capture_output=True) found_sumo = not check_sumo.stdout == b'' found_band_data = os.path.exists(os.path.join(wd, 'vasprun.xml')) if found_sumo and found_band_data: os.chdir(wd) sumo_cmd = ['sumo-bandplot'] run_sumo = sp.run(sumo_cmd, capture_output=True) if outfile is not None: shutil.copy('band.pdf', outfile) else: outfile = 'band.pdf' if outdir is not None: target = os.path.join(outdir, outfile) shutil.copy(outfile, target) else: target = os.path.join(os.getcwd(), outfile) Egap, Ecbm, Evbm = read_bandstats() else: print('sumo-bandplot not found. No band plot generated.') target = None Egap, Ecbm, Evbm = None, None, None #reset dir os.chdir(prevdir) return (npoints, band_energies, fig, Egap, Ecbm, Evbm)
def get_bandstructure_v02(self, kpts_path=None, kpts_nintersections=None, show=False, outdir=None, outfile=None): """Calculate a hybrid band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. returns (npoints, band_energies, fighandle) This is designed to provide a function to calculate the band structure according to the procedure 2 provided by the VASP Wiki: https://www.vasp.at/wiki/index.php/Si_bandstructure#Procedure_2:_0-weight_.28Fake.29_SC_procedure_.28PBE_.26_Hybrids.29 """ """ Our first job will be to copy the working directory to a subdirectory. This will happen on the first invocation of get_bandstructure_v02() """ self.update() self.stop_if(self.potential_energy is None) kx, ky, kz, labels, label_idx = interpolate_kpath(kpts_path, kpts_nintersections) num_new_k_points = len(kx) ''' kx = np.linspace(kpts[0][0], kpts[1][0], kpts_nintersections) ky = np.linspace(kpts[0][1], kpts[1][1], kpts_nintersections) kz = np.linspace(kpts[0][2], kpts[1][2], kpts_nintersections) ''' dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() ''' By now, our initial DFT calculation should be complete. It should have produced an IBZKPT file. ''' wd = os.path.join(self.directory, 'bandstructure') if not os.path.exists(wd): # I think: clone works if no subsequent calcs have been run # This branch should be taken on the first invocation of # get_bandstructure_v02 self.clone(wd) # I think: Vasp() works if no subsequent calcs have been run calc = Vasp(wd) ''' Now we create a file "KPOINTS_HSE_bands" update the KPOINTS file by doing the following: (1) Use the IBZKPT file for the KPOINTS file (2) Add desired zero-weight k-points (3) Update the number of total k-points Here's a link to a video of a seminar where the additional k-points are discussed: https://youtu.be/OQhRYzWAGfk?t=2389 - These points correspond to positions along the k-point path we desire ''' # Deleting the old KPOINTS file is probably a bad thing # old_kpts = os.path.join( calc.directory, 'KPOINTS') # os.remove(old_kpts) # Read the automatically-generated k-points from IBZKPT IBZKPT = os.path.join(calc.directory, 'IBZKPT') with open(IBZKPT, 'rt') as infile: infile.readline() nk_old = int(infile.readline().split()[0]) # print(nk_old) print(f'Found {nk_old} k-points in IBZKPT.') print( f'There are {num_new_k_points} additional zero-weight k-points.' ) print('Reading the original k-points...') original_k_lines = [] for idx in range(0, nk_old + 1): original_k_lines.append(infile.readline()) # print(': {0}'.format(original_k_lines[idx])) total_k_points = nk_old + num_new_k_points print(f'There are a total of {total_k_points} k-points.') # Obtain text lines for the original k-points HSE_lines = [ 'Explicit k-point list\n', ' ' * 6 + f'{total_k_points}\n' ] for line in original_k_lines: HSE_lines.append(line) # Make text lines for the new k points for idx in range(0, num_new_k_points): line_str = '{0:15.12f} {1:15.12f} {2:15.12f} 0.0\n'.format( kx[idx], ky[idx], kz[idx]) HSE_lines.append(line_str) # for line in HSE_lines: # print(line) # Write the 'KPOINTS_HSE_bands' file tgt = os.path.join(calc.directory, 'KPOINTS') # 'KPOINTS_HSE_bands') with open(tgt, 'w') as KPTSfile: for line in HSE_lines: KPTSfile.write(line) """ Refer to: https://www.vasp.at/wiki/index.php/Si_bandstructure#Hybrid_calculation_using_a_suitably_modified_KPOINTS_file Here, the VASP example suggests adding the following to the INCAR file: ## HSE LHFCALC = .TRUE. ; HFSCREEN = 0.2 ; AEXX = 0.25 ALGO = D ; TIME = 0.4 ; LDIAG = .TRUE. Notes: validate.py does not appear to have a case for LHFCALC, HFSCREEN, or AEXX. This might necessitate (for now), the simple and dirty hack of simply appending text to the INCAR file. This, then, means another dirty hack of running VASP in the directory in question apart from ASE. LHFCALC (https://www.vasp.at/wiki/index.php/LHFCALC) specifies whether HF/DFT hybrid functional-type calculations are performed. Default: False HFSCREEN (https://www.vasp.at/wiki/index.php/HFSCREEN) specifies the range-separation parameter in range separated hybrid functionals. AEXX (https://www.vasp.at/wiki/index.php/AEXX) Default: AEXX = 0.25 if LHFCALC=.TRUE., 0 otherwise The ALGO (https://www.vasp.at/wiki/index.php/ALGO) Wiki page does not list a "D" property. There is a "Damped" setting, however. The LDIAG (https://www.vasp.at/wiki/index.php/LDIAG) page says that TRUE is the default value, so I'm going to refrain from adding this. """ HSE_settings = 'LHFCALC = .TRUE. ; HFSCREEN = 0.2; ALGO = D\nICHARG = 11' tgt = os.path.join(calc.directory, 'INCAR') with open(tgt, 'a') as infile: infile.write(HSE_settings) # Create and run a subprocess that invokes if self.parameters.get('lsorbit'): runfile = 'runvasp_ncl.py' else: runfile = 'runvasp.py' CWD = os.getcwd() VASPDIR = calc.directory from .vasprc import VASPRC module = VASPRC['module'] script = """#!/bin/bash module load {module} source ~/.bashrc # added by EPB - slight issue with "module load intel" cd {CWD} cd {VASPDIR} # this is the vasp directory {runfile} # this is the vasp command #end""".format(**locals()) jobname = 'HSE_BandCalc' cmdlist = ['{0}'.format(VASPRC['queue.command'])] cmdlist += ['-o', VASPDIR] cmdlist += [option for option in VASPRC['queue.options'].split()] cmdlist += [ '-N', '{0}'.format(jobname), '-l', 'walltime={0}'.format(VASPRC['queue.walltime']), '-l', 'nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn']), '-l', 'mem={0}'.format(VASPRC['queue.mem']), '-M', VASPRC['user.email'] ] p = sp.Popen(cmdlist, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True) out, err = p.communicate(script) return None else: """ This should happen on the second invocation of get_bandstructure_v02. Here, we will add labels for the zero-weight k-points. """ # Read the automatically-generated k-points from IBZKPT IBZKPT = os.path.join(wd, 'IBZKPT') with open(IBZKPT, 'rt') as infile: infile.readline() nk_old = int(infile.readline().split()[0]) # print(nk_old) print(f'Found {nk_old} k-points in IBZKPT.') kx, ky, kz, spec_k_labels, label_idx = interpolate_kpath( kpts_path, kpts_nintersections) num_new_k_points = len(kx) import shutil archive_KPOINTS = os.path.join(wd, 'KPOINTS_original') if not os.path.exists(archive_KPOINTS): shutil.copy(os.path.join(wd, 'KPOINTS'), archive_KPOINTS) with open(archive_KPOINTS, 'r') as infile: KPTS_Lines = infile.readlines() for idx, label in enumerate(spec_k_labels): label = label.replace('$', '') newk_idx = label_idx[idx] line_with_label = KPTS_Lines[3 + nk_old + newk_idx][:-1] + f' {label}\n' KPTS_Lines[3 + nk_old + newk_idx] = line_with_label with open(os.path.join(wd, 'KPOINTS'), 'w') as KPOINTSfile: for line in KPTS_Lines: KPOINTSfile.write(line) # Run sumo-bandplot, if it exists check_sumo = sp.run(['which', 'sumo-bandplot'], capture_output=True) found_sumo = not check_sumo.stdout == b'' found_band_data = os.path.exists(os.path.join(wd, 'vasprun.xml')) if found_sumo and found_band_data: os.chdir(wd) sumo_cmd = ['sumo-bandplot'] run_sumo = sp.run(sumo_cmd, capture_output=True) if outfile is not None: shutil.copy('band.pdf', outfile) else: outfile = 'band.pdf' if outdir is not None: target = os.path.join(outdir, outfile) shutil.copy(outfile, target) else: target = os.path.join(os.getcwd(), outfile) Egap, Ecbm, Evbm = read_bandstats() else: print('sumo-bandplot not found. No band plot generated.') target = None Egap, Ecbm, Evbm = None, None, None return {'file': target, 'Egap': Egap, 'Ecbm': Ecbm, 'Evbm': Evbm}
def get_supercell_bandstructure_ppc(self, kpts_path=None, kpts_nintersections=None, supercell_size=[1, 1, 1], unit_cell=[[1.0, 0, 0], [0, 1.0, 0], [0.0, 0.0, 0.0]], show=False): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. :param list supercell_size: this lists the size of the supercell [nx ny nz] as multiples of the unit cell in the ordinal directions :param list unit_cell: list of unit cell vectors This version uses PyProcar for k-path preparation and unfolding. See https://romerogroup.github.io/pyprocar/index.html returns (npoints, band_energies, fighandle) """ self.update() self.stop_if(self.potential_energy is None) M = [[1.0 * supercell_size[0], 0.0, 0.0], [0.0, 1.0 * supercell_size[1], 0.0], [0.0, 0.0, 1.0 * supercell_size[2]]] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] # by now, the self-consistent calculation is complete # run in non-selfconsistent directory wd = os.path.join(self.directory, 'bandstructure') if not os.path.exists(wd): self.clone(wd) calc = Vasp(wd) # this next line actually writes a K-points file, but we're # going to use pyprocar to overwrite it calc.set( kpts=kpts, kpts_nintersections=10, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, icharg=11, lorbit=12) os.remove(os.path.join(wd, 'KPOINTS')) # Let's try generating the default k-points path # Now I need to learn how to set the k-path using pyprocar # see: import pyprocar as ppc ppc.kpath(os.path.join(wd, 'POSCAR'), os.path.join(wd, 'KPOINTS'), supercell_matrix=np.diag(supercell_size)) # calc.update() # we'll just launch VASP - skip the calc.update() # Create and run a subprocess that invokes if self.parameters.get('lsorbit'): runfile = 'runvasp_ncl.py' else: runfile = 'runvasp.py' CWD = os.getcwd() VASPDIR = calc.directory from .vasprc import VASPRC module = VASPRC['module'] script = """#!/bin/bash module load {module} source ~/.bashrc # added by EPB - slight issue with "module load intel" cd {CWD} cd {VASPDIR} # this is the vasp directory {runfile} # this is the vasp command #end""".format(**locals()) jobname = 'SCBands' cmdlist = ['{0}'.format(VASPRC['queue.command'])] cmdlist += ['-o', VASPDIR] cmdlist += [option for option in VASPRC['queue.options'].split()] cmdlist += [ '-N', '{0}'.format(jobname), '-l', 'walltime={0}'.format(VASPRC['queue.walltime']), '-l', 'nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn']), '-l', 'mem={0}'.format(VASPRC['queue.mem']), '-M', VASPRC['user.email'] ] p = sp.Popen(cmdlist, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True) out, err = p.communicate(script) ''' return None, None, None # if calc.potential_energy is None: # return None, None, None else: # I don't think this will work unless the calculation is complete! os.chdir(wd) import pyprocar pyprocar.unfold( fname='PROCAR', poscar='POSCAR', outcar='OUTCAR', supercell_matrix=np.diag(supercell_size), ispin=None, # None for non-spin polarized calculation. For spin polarized case, ispin=1: up, ispin=2: down efermi=None, shift_efermi=True, elimit=(-2, 2), # kticks=[0, 36, 54, 86, 110, 147, 165, 199], knames=['$\Gamma$', 'K', 'M', '$\Gamma$', 'A', 'H', 'L', 'A'], print_kpts=False, show_band=True, width=4, color='blue', savetab='unfolding.csv', savefig='unfolded_band.png', exportplt=False) return None, None, None ''' from unfold import unfold WaveSuper = unfold(M=M, wavecar='WAVECAR') sw = WaveSuper.spectral_weight(kpath_uc) from unfold import EBS_cmaps e0, sf = WaveSuper.spectral_function(nedos=4000) # or show the effective band structure with colormap EBS_cmaps( kpath_sc, unit_cell, e0, sf, nseg=nseg, # eref=-4.01, show=False) #, # ylim=(-3, 4)) ''' plt.savefig('unfolded_bandstructure.png') ''' # In the fol archiveKpts = os.path.join(wd, 'KPOINTS_old') originalKpts = os.path.join(wd, 'KPOINTS') if not os.path.exists( archiveKpts): # archive the original KPOINTS file shutil.copy(originalKpts, archiveKpts) with open(archiveKpts, 'r') as kpts_infile: # get lines of old KPOINTS KPtsLines = kpts_infile.readlines() # Append labels for high-symmetry points to lines of the KPOINTS file reject_chars = '$' for idx, label in enumerate(labels): newlabel = label for ch in reject_chars: newlabel = newlabel.replace(ch, '') KPtsLines[4 + idx] = KPtsLines[4 + idx][:-1] + f' ! {newlabel}\n' # Write a new version of the k-points file with open(originalKpts, 'w') as kpts_outfile: for line in KPtsLines: kpts_outfile.write(line) # This is John Kitchin's original band structure visualization fig = plt.figure() with open(os.path.join(wd, 'EIGENVAL')) as f: # skip 5 lines f.readline() f.readline() f.readline() f.readline() f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] f.readline() # skip line band_energies = [[] for i in range(nbands)] for i in range(npoints): x, y, z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id - 1].append(energy) f.readline() # skip line ax1 = plt.subplot(121) for i in range(nbands): plt.plot(list(range(npoints)), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels) / 2 + 1 ax.set_xticks(np.linspace(0, npoints, nticks)) L = [] L.append(labels[0]) for i in range(2, len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0, c='r') plt.subplot(122, sharey=ax1) plt.plot(d, e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) if show: plt.show() return (npoints, band_energies, fig)
def get_supercell_bandstructure(self, kpts_path=None, kpts_nintersections=None, supercell_size=[1, 1, 1], unit_cell=[[1.0, 0, 0], [0, 1.0, 0], [0.0, 0.0, 1.0]], show=False, imagedir=None, imageprefix=None, eref=None, ymin=None, ymax=None, lsorb=False): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. :param list supercell_size: this lists the size of the supercell [nx ny nz] as multiples of the unit cell in the ordinal directions :param list unit_cell: list of unit cell vectors returns (npoints, band_energies, fighandle) """ self.update() self.stop_if(self.potential_energy is None) # Determine whether the colinear (vasp_std) or non-colinear (vasp_ncl) is # to be used if self.parameters.get('lsorbit'): runfile = 'runvasp_ncl.py' else: runfile = 'runvasp.py' ''' I'm following the procedure for creating a k-path in the supercell https://github.com/QijingZheng/VaspBandUnfolding#band-unfolding-1 ''' # The tranformation matrix between supercell and primitive cell. M = [[1.0 * supercell_size[0], 0.0, 0.0], [0.0, 1.0 * supercell_size[1], 0.0], [0.0, 0.0, 1.0 * supercell_size[2]]] print(M) from unfold import find_K_from_k, make_kpath, removeDuplicateKpoints # Extract unit-cell k-points from kpts_path uc_k_pts_bare = [k[1] for k in kpts_path] nseg = 30 # points per segment kpath_uc = make_kpath(uc_k_pts_bare, nseg=nseg) # interpolated uc k-path # Map UC (=PC) k-points to SC k-points Kpath_sc = [] for k_uc in kpath_uc: K, g = find_K_from_k(k_uc, M) Kpath_sc.append(K) # add a weight to K Kpath = removeDuplicateKpoints(Kpath_sc) # this is a numpy.ndarray # I convert this to a list because the Vasp wrapper prefers a kpts list # Also, the Vasp wrapper wants a weight for each K point Kpath_list = [list(np.append(K, 1.0)) for K in Kpath] # Extract (unit cel) labels from kpts_path labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() print(f'Fermi energy: {ef:8.3f} eV') # run in non-selfconsistent directory wd = os.path.join(self.directory, 'bandstructure') if not os.path.exists(wd): self.clone(wd) calc = Vasp(wd) # don't set kpts_nintersections - avoid line mode calc.set( kpts=Kpath_list, reciprocal=True, nsw=0, # no ionic updates required ismear=0, sigma=0.1, isif=None, ibrion=None, icharg=11, lorbit=12) calc.update() # updates the calculation files # The manual calculation might be unnecessary because # of the calc.update() ''' CWD = os.getcwd() VASPDIR = calc.directory from .vasprc import VASPRC module = VASPRC['module'] script = """#!/bin/bash module load {module} source ~/.bashrc # added by EPB - slight issue with "module load intel" cd {CWD} cd {VASPDIR} # this is the vasp directory {runfile} # this is the vasp command #end""".format(**locals()) jobname = 'SCBands' cmdlist = ['{0}'.format(VASPRC['queue.command'])] cmdlist += ['-o', VASPDIR] cmdlist += [option for option in VASPRC['queue.options'].split()] cmdlist += ['-N', '{0}'.format(jobname), '-l', 'walltime={0}'.format(VASPRC['queue.walltime']), '-l', 'nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn']), '-l', 'mem={0}'.format(VASPRC['queue.mem']), '-M', VASPRC['user.email']] p = sp.Popen(cmdlist, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True) out, err = p.communicate(script) ''' return None, None else: # I don't think this will work unless the calculation is complete! os.chdir(wd) if imagedir is None: imagedir = os.getcwd() if imageprefix is None: imageprefix = 'unfolded_bandstructure' from unfold import unfold # nseg = len(kpts_path) -1 WaveSuper = unfold(M=M, wavecar='WAVECAR', lsorbit=lsorb) sw = WaveSuper.spectral_weight(kpath_uc) from unfold import EBS_cmaps, EBS_scatter e0, sf = WaveSuper.spectral_function(nedos=4000) if eref is None: eref = ef if ymin is None: ymin = ef - 5 if ymax is None: ymax = ef + 5 print('The unit cell vectors are:') print(unit_cell) # Show the effective band structure with a scatter plot EBS_scatter(kpath_uc, unit_cell, sw, nseg=nseg, eref=eref, ylim=(ymin, ymax), factor=5, kpath_label=labels) scatterplot = os.path.join(imagedir, imageprefix) + '_scatter_plot.png' plt.savefig(scatterplot) plt.close('all') # or show the effective band structure with colormap EBS_cmaps(kpath_uc, unit_cell, e0, sf, nseg=nseg, eref=eref, show=False, ylim=(ymin, ymax), kpath_label=labels) colormap = os.path.join(imagedir, imageprefix) + '_colormap.png' plt.savefig(colormap) return scatterplot, colormap
symbol='Ni') atoms[0].magmom = 1 calc = Vasp( 'bulk/Ni-PBE', ismear=-5, kpts=[5, 5, 5], xc='PBE', ispin=2, lorbit=11, lwave=True, lcharg=True, # store for reuse atoms=atoms) e = atoms.get_potential_energy() print('PBE energy: ', e) calc.stop_if(e is None) dos = DOS(calc, width=0.2) e_pbe = dos.get_energies() d_pbe = dos.get_dos() calc.clone('bulk/Ni-PBE0') calc.set(xc='pbe0') atoms = calc.get_atoms() pbe0_e = atoms.get_potential_energy() if atoms.get_potential_energy() is not None: dos = DOS(calc, width=0.2) e_pbe0 = dos.get_energies() d_pbe0 = dos.get_dos() ## HSE06 calc = Vasp('bulk/Ni-PBE') calc.clone('bulk/Ni-HSE06') calc.set(xc='hse06') atoms = calc.get_atoms()
import numpy as np from ase.dft import DOS class MyCalc: def get_eigenvalues(self, kpt=0, spin=0): return np.random.uniform(-5.0, 2.0, 90) def get_k_point_weights(self): return [1.0] def get_number_of_spins(self): return 1 def get_fermi_level(self): return 0.0 calc = MyCalc() dos = DOS(calc, width=0.2) d = dos.get_dos() e = dos.get_energies() import matplotlib matplotlib.use('Agg') import pylab as plt plt.figure(figsize=(5, 4)) plt.plot(e, d) plt.xlabel('energy [eV]') plt.ylabel('DOS') plt.savefig('dos.png')
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10, show=False): """Calculate band structure along :param kpts_path: :param list kpts_path: list of tuples of (label, k-point) to calculate path on. :param int kpts_nintersections: is the number of points between points in band structures. More makes the bands smoother. returns (npoints, band_energies, fighandle) """ self.update() self.stop_if(self.potential_energy is None) kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory wd = os.path.join(self.directory, 'bandstructure') self.clone(wd) calc = vasp.Vasp(wd) calc.set( kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, icharg=11) calc.update() if calc.potential_energy is None: return None, None, None fig = plt.figure() with open(os.path.join(wd, 'EIGENVAL')) as f: # skip 5 lines f.readline() f.readline() f.readline() f.readline() f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] f.readline() # skip line band_energies = [[] for i in range(nbands)] for i in range(npoints): x, y, z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id - 1].append(energy) f.readline() # skip line ax1 = plt.subplot(121) for i in range(nbands): plt.plot(range(npoints), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels) / 2 + 1 ax.set_xticks(np.linspace(0, npoints, nticks)) L = [] L.append(labels[0]) for i in range(2, len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0, c='r') plt.subplot(122, sharey=ax1) plt.plot(d, e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) if show: plt.show() return (npoints, band_energies, fig)
def get_dos(self, atoms=None, spin=None, width=0.1, npts=201): from ase.dft import DOS dos = DOS(self, width=width, npts=npts) return dos.get_energies(), dos.get_dos(spin)
def makedb(calc, atoms=None, dbname='data.db', overwrite=False, dos=False, ados=False, keys={}, data={}, **kwargs): '''Make a modular database in calculator directory. This function generates useful key-value-pairs based on the directory path the calculation is stored in. i.e. .DFT/bulk=Ag/lattice=4.06/ will create two key-value-pairs: bulk=Ag and lattice=4.06 more information on ASE database can be found here: https://wiki.fysik.dtu.dk/ase/ase/db/db.html''' # Do not run if database already exists if os.path.exists(dbname) and overwrite: os.unlink(dbname) # Get keys_value_pairs from directory name. # Collect only path names with '=' in them. path = [x for x in os.getcwd().split('/') if '=' in x] for key_value in path: key = key_value.split('=')[0] value = key_value.split('=')[1] # Try to recognize characters and convert to # specific data types for easy access later. if '.' in value: value = float(value) elif value.isdigit(): value = int(value) elif value == 'False': value = bool(False) elif value == 'True': value = bool(True) else: value = str(value) # Add directory keys keys[key] = value # Add DFT parameters to key-value-pairs data.update(dict(filter(lambda item: item[1] is not None, calc.float_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.int_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.bool_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.exp_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.special_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.string_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.bool_params.items()))) data.update(dict(filter(lambda item: item[1] is not None, calc.dict_params.items()))) # Store k-points individually data['volume'] = atoms.get_volume() data['path'] = os.getcwd() try: data['fermi'] = calc.get_fermi_level() except(AttributeError): pass # Get the atoms object from the calculator if atoms is None: atoms = calc.get_atoms() if hasattr(calc, 'spinpol'): if calc.spinpol: data['final_magmom'] = atoms.get_magnetic_moment() if calc.is_neb(): keys['image'] = int(calc.vaspdir.split('/')[-1]) # Add density of state information to the dictionary if dos: dos = DOS(calc) d = dos.get_dos() e = dos.get_energies() data['DOS'] = {} data['DOS']['states'] = d data['DOS']['energy'] = e data['dband_center'] = np.trapz(e * d, e) / np.trapz(d, e) data['dband_width'] = np.trapz(e**2 * d, e) / np.trapz(d, e) # Add density of state information to the dictionary if ados: ados = VaspDos(efermi=calc.get_fermi_level()) d = {} e = ados.energy for orb in ['s', 'p', 'd']: d[orb] = {} for atom in atoms: ind = calc.resort[atom.index] d[orb][ind] = ados.site_dos(ind, orb) data['ADOS'] = {} data['ADOS']['states'] = d data['ADOS']['energy'] = e # Add calculation time to key-value-pairs try: data['calc_time'] = float(get_elapsed_time(calc)) except(AttributeError, IOError): data['calc_time'] = float(0.0) # Generate the JSON file db = connect(dbname) db.write(atoms=atoms, key_value_pairs=keys, data=data)
def get_bandstructure(self, kpts_path=None, kpts_nintersections=10): kpts = [k[1] for k in kpts_path] labels = [k[0] for k in kpts_path] dos = DOS(self, width=0.2) d = dos.get_dos() e = dos.get_energies() ef = self.get_fermi_level() # run in non-selfconsistent directory cwd = os.getcwd() base, end = os.path.split(cwd) wd = cwd + '/bandstructure' self.clone(wd) with jasp(wd, kpts=kpts, kpts_nintersections=kpts_nintersections, reciprocal=True, nsw=0, # no ionic updates required isif=None, ibrion=None, debug=logging.DEBUG, icharg=11) as calc: calc.calculate() fig = plt.figure() with open('EIGENVAL') as f: line1 = f.readline() line2 = f.readline() line3 = f.readline() line4 = f.readline() comment = f.readline() unknown, npoints, nbands = [int(x) for x in f.readline().split()] blankline = f.readline() band_energies = [[] for i in range(nbands)] for i in range(npoints): x,y,z, weight = [float(x) for x in f.readline().split()] for j in range(nbands): fields = f.readline().split() id, energy = int(fields[0]), float(fields[1]) band_energies[id-1].append(energy) blankline = f.readline() f.close() ax1 = plt.subplot(121) for i in range(nbands): plt.plot(range(npoints), np.array(band_energies[i]) - ef) ax = plt.gca() ax.set_xticks([]) # no tick marks plt.xlabel('k-vector') plt.ylabel('Energy (eV)') nticks = len(labels)/2 + 1 ax.set_xticks(np.linspace(0,npoints,nticks)) L = [] L.append(labels[0]) for i in range(2,len(labels)): if i % 2 == 0: L.append(labels[i]) else: pass L.append(labels[-1]) ax.set_xticklabels(L) plt.axhline(0,c='r') plt.subplot(122, sharey=ax1) plt.plot(d,e) plt.axhline(0, c='r') plt.ylabel('energy (eV)') plt.xlabel('DOS') plt.subplots_adjust(wspace=0.26) plt.show() return (npoints, band_energies, fig)