Electronic structure

Overview

Teaching: 20 min
Exercises: 20 min
Questions
  • How can I use DFT to produce an electronic bandstructure?

  • How can I use DFT to produce an electronic Density of States?

Objectives

Code connection

In this episode we will use Quantum Espresso to calculate the electronic structure (bandstructure and density of states) of silicon. We will analyse and plot the electronic structure using ase.dft and ase.spectrum.

We now have all the tools in place to calculate electronic structure properties

Note

This is not a course in DFT; for more details on the terminology used please see other sources.

The tocell() method can be used to build a FCC lattice

from ase import Atoms
from ase.lattice import FCC
from ase.units import Bohr

si_fcc = Atoms(symbols='Si2',
               cell = FCC(a=10.20*Bohr).tocell(),
               scaled_positions=[(0.0, 0.0, 0.0),
                                 (0.25, 0.25, 0.25)],
               pbc=True)

Pseudopotential data are loaded from a local filepath

Note

This is not a course in DFT; be aware that calculation parameters must be chosen with care for a given research problem.

from pathlib import Path
import json

pseudo_dir = Path.home() / 'SSSP_1.2.1_PBE_efficiency'
with open(str(pseudo_dir / 'SSSP_1.2.1_PBE_efficiency.json')) as fj:
  dj = json.load(fj) 
ecutwfc = dj['Si']['cutoff_wfc']
ecutrho = dj['Si']['cutoff_rho']

atomic_species = {'Si':dj['Si']['filename']}
control = {'calculation': "scf",
           'prefix': "si_fcc",
           'outdir': str(Path('./si_fcc/out').absolute()) ,
           'pseudo_dir': str(pseudo_dir),
           'tprnfor': True,
           'tstress': True}
system = {'ecutwfc': ecutwfc,
          'ecutrho': ecutrho}
electrons = {'diagonalization':'davidson',
             'conv_thr': 1.e-8}

EspressoProfile objects are used to hold run information

from ase.calculators.espresso import EspressoProfile

plain_argv = ['mpirun', '-np', '4', 'pw.x']
pools_argv = ['-nk', '4']
profile = EspressoProfile(plain_argv)
profile_4pools = EspressoProfile(plain_argv + pools_argv)    

Specify a directory for each calculation to avoid overwriting

from ase.calculators.espresso import Espresso 

scf_directory = Path('./si_fcc/scf/').absolute()

scf_calc = Espresso(directory=scf_directory,
                profile=profile,
                input_data={'control': control,
                            'system': system,
                            'electrons': electrons},
                pseudopotentials={'Si':dj['Si']['filename']},
                kpts=[8,8,8],
                koffset=[1,1,1])
si_fcc.calc = scf_calc
props_scf = si_fcc.get_properties(['energy'])
round(props_scf['energy'],8) 
-215.69011555

Generate k-points path using the bandpath method

kpointpath = si_fcc.cell.bandpath(path='LGXWKG', density=20)
kpointpath.special_points
{'G': array([0., 0., 0.]),
 'K': array([0.375, 0.375, 0.75 ]),
 'L': array([0.5, 0.5, 0.5]),
 'U': array([0.625, 0.25 , 0.625]),
 'W': array([0.5 , 0.25, 0.75]),
 'X': array([0.5, 0. , 0.5])}

Create a new Calculator object and Atoms for the next calculation

control.update({'calculation':"bands"})
system.update({'nbnd':12})
electrons.update({'conv_thr': 1.e-6})
bands_directory = Path('./si_fcc/bands').absolute()

bands_calc = Espresso(directory=bands_directory,
                  input_data={'control': control,
                              'system': system,
                              'electrons':electrons},
                  pseudopotentials=atomic_species, 
                  profile=profile_4pools,
                  kpts=kpointpath) 
si_fcc_bands = si_fcc.copy()
si_fcc_bands.calc = bands_calc
results_bands = si_fcc_bands.get_properties(['eigenvalues']) 

Use ase.spectrum to analyse and plot band structures

from ase.spectrum.band_structure import BandStructure
si_fcc_band_structure = BandStructure(path=kpointpath, 
                           energies=results_bands['eigenvalues'], reference=si_fcc.calc.get_fermi_level())
bandplot = si_fcc_band_structure.plot(emin=-6, emax=15)
bandplot.figure.savefig('band_structure_Si.png')

Bandstructure plot for Si

Use ase.dft to compute the Density of States

control.update({'calculation':'nscf',
                'verbosity': 'high'})
system.update({'nbnd': 20})

nscf_directory = Path('./si_fcc/nscf').absolute() 

nscf_calc = Espresso(directory =nscf_directory,
                 profile = profile_4pools,
                 input_data={'control': control,
                             'system': system,
                             'electron': electrons}, 
                 pseudopotentials=atomic_species, 
                 kpts=[16,16,16],
                 koffset=[0,0,0]) 

si_fcc_nscf = si_fcc.copy()
si_fcc_nscf.calc = nscf_calc
nscf_results = si_fcc_nscf.get_properties(['eigenvalues'])
from ase.dft.dos import DOS 
from matplotlib  import pyplot as plt

dos = DOS(nscf_calc, npts = 200,width=0.2) 
energies=dos.energies
dosvals = dos.get_dos() 

plt.plot(energies, dosvals)
plt.axis([-13, 15, 0, 5])
plt.savefig('DOS_Si.png')

Electronic density of states for Si

Key Points

  • We now have all the tools in place to calculate electronic structure properties

  • Use the tocell() method to build a FCC lattice

  • Pseudopotential data are loaded from a local filepath

  • Python dictionaries are used to store related calculation parameters

  • EspressoProfile objects are used to hold run information

  • Specify a directory for each calculation to avoid overwriting

  • Generate k-points path using the bandpath method

  • Create a new Calculator object and Atoms for the next calculation

  • Use ase.spectrum to analyse and plot band structures

  • Use ase.dft to compute the Density of States