Benchmark: density functionals and settings for band gaps
Jetsabel Figueroa, MSc. student in the OptoElectronics group at the TU Delft, benchmarked band gap calculations with BAND.
During her internship with SCM she made use of the python scripting tool PLAMS (see the script with recommended settings at the end of this article) determine the best exchange-correlation functionals for determining band gaps of insulators and semi-conductors. Testing a set of 59 materials, she furthermore studied convergence of band gaps with respect to basis sets and k-point sampling.
Summary: recommended settings for band gap calculations
For accurate band gaps, the TB-mBJ model potential (Physical Review Letters 102, 226401 (2009)) is recommended, with the computational more demanding HSE06 giving similar results. A TZP basis set with a small core and ‘good’ k-point sampling is recommended. For large band gap insulators a normal k-point sampling may also suffice. Spin-orbit coupling will affect band gaps of materials containing heavy elements. A sizable effect was reported for all systems containing Cu or heavier elements. For other systems, scalar ZORA is sufficient. Specifically systems with heavy main group elements (In, Sn, Ga, Sb, Te, Br, Pb, …) have strong spin-orbit coupling effects. See the report for more details. You may also consider the more recent KTB-mBJ parametrization.
Python script (PLAMS) for screening material band gaps with recommended settings
import os import sys coord_dir = '/path_to_xyz_files' # Settings for the Band calculation: sett = Settings() sett.input.Units.length = 'Angstrom' sett.input.BasisDefaults.BasisType = 'TZP' sett.input.BasisDefaults.core = 'None' sett.input.KSpace.Quality = 'Good' sett.input.XC.Model = 'TB-mBJ' sett.input.Relativistic = 'Scalar ZORA' for root, dirs, filenames in os.walk(coord_dir): for f in filenames: crystalName = os.path.basename(f).rsplit('.')[0] mol = Molecule(os.path.join(root, f)) # Create and run the job: job = BANDJob(molecule=mol, settings=sett) job.run() if job.check(): bandgap_au = job.results.readkf('BandStructure','BandGap') bandgap_ev = Units.convert(bandgap_au, 'Hartree', 'eV') print(crystalName, 'Bandgap: %f eV' % bandgap_ev) else: print("job crashed ;", crystalName) print(job.results.grep_output('ERROR')) sys.stdout.flush()