def calculate_bandstructure(self, bs): """ Returns a BandStructure object with a DFTB band structure. Assumes that the necessary *-*.skf files have been generated. bs: ase.dft.band_structure.BandStructure instance with an additional 'atoms' and 'kpts_scf' attributes. The latter represents the k-points to be used in the self-consistent calculation prior to the bandstructure calculation in DFTB. """ # Perform a regular DFTB calculation first # to converge the charges and get the # reference energy atoms = bs.atoms.copy() calc = Dftb(atoms=atoms, kpts=bs.kpts_scf, **self.dftbplus_kwargs) atoms.set_calculator(calc) etot = atoms.get_potential_energy() efermi = calc.get_fermi_level() if bs.reference_level == 'vbm': eig = np.array(calc.results['eigenvalues']) eref = np.max(eig[eig < efermi]) elif bs.reference_level == 'fermi': eref = efermi # Now a band structure calculation kwargs = self.dftbplus_kwargs.copy() kwargs.update({ 'Hamiltonian_MaxSCCIterations': 1, 'Hamiltonian_ReadInitialCharges': 'Yes', 'Hamiltonian_SCCTolerance': 1e6 }) calc = Dftb(atoms=atoms, kpts=bs.path.kpts, **kwargs) atoms.set_calculator(calc) etot = atoms.get_potential_energy() # Update the reference level, k-points, # and eigenenergies bs_new = copy.deepcopy(bs) #bs_new.reference = eref bs_new_reference = eref bs_new.kpts = calc.get_ibz_k_points() #bs_new.energies = [] bs_new_energies = [] for s in range(calc.get_number_of_spins()): #bs_new.energies.append([calc.get_eigenvalues(kpt=k, spin=s) bs_new_energies.append([ calc.get_eigenvalues(kpt=k, spin=s) for k in range(len(bs_new.kpts)) ]) #bs_new.energies = np.array(bs_new.energies) bs_new_energies = np.array(bs_new_energies) return bs_new
if '17.1' not in version: msg = 'Band structure properties not present in results.tag for ' + version raise SkipTest(msg) # The actual testing starts here calc = Dftb(label='dftb', kpts=(3, 3, 3), Hamiltonian_SCC='Yes', Hamiltonian_SCCTolerance=1e-5, Hamiltonian_MaxAngularMomentum_Si='d') atoms = bulk('Si') atoms.set_calculator(calc) atoms.get_potential_energy() efermi = calc.get_fermi_level() assert abs(efermi - -2.90086680996455) < 1. # DOS does not currently work because of # missing "get_k_point_weights" function #from ase.dft.dos import DOS #dos = DOS(calc, width=0.2) #d = dos.get_dos() #e = dos.get_energies() #print(d, e) calc = Dftb(atoms=atoms, label='dftb', kpts={ 'path': 'WGXWLG', 'npoints': 50
def test_dftb_bandstructure(): import os import subprocess from unittest import SkipTest from ase.test import require from ase.test.testsuite import datafiles_directory from ase.calculators.dftb import Dftb from ase.build import bulk require('dftb') os.environ['DFTB_PREFIX'] = datafiles_directory # We need to get the DFTB+ version to know # whether to skip this test or not. # For this, we need to run DFTB+ and grep # the version from the output header. cmd = os.environ['ASE_DFTB_COMMAND'].split()[0] proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) lines = '' for line in proc.stdout: l = line.decode() if 'DFTB+' in l and ('version' in l.lower() or 'release' in l.lower()): version = l[l.index('DFTB+'):] break lines += l + '\n' else: raise RuntimeError('Could not parse DFTB+ version ' + lines) if '17.1' not in version: msg = 'Band structure properties not present in results.tag for ' + version raise SkipTest(msg) # The actual testing starts here calc = Dftb(label='dftb', kpts=(3, 3, 3), Hamiltonian_SCC='Yes', Hamiltonian_SCCTolerance=1e-5, Hamiltonian_MaxAngularMomentum_Si='d') atoms = bulk('Si') atoms.set_calculator(calc) atoms.get_potential_energy() efermi = calc.get_fermi_level() assert abs(efermi - -2.90086680996455) < 1. # DOS does not currently work because of # missing "get_k_point_weights" function #from ase.dft.dos import DOS #dos = DOS(calc, width=0.2) #d = dos.get_dos() #e = dos.get_energies() #print(d, e) calc = Dftb(atoms=atoms, label='dftb', kpts={ 'path': 'WGXWLG', 'npoints': 50 }, Hamiltonian_SCC='Yes', Hamiltonian_MaxSCCIterations=1, Hamiltonian_ReadInitialCharges='Yes', Hamiltonian_MaxAngularMomentum_Si='d') atoms.set_calculator(calc) calc.calculate(atoms) calc.results['fermi_levels'] = [efermi] calc.band_structure()