GW approximation

Modules: pyscf.gw, pyscf.pbc.gw

Introduction

The GW approximation is a Green’s function-based method that calculates charged excitation energies, i.e. ionizations potentials (IPs) and electron affinities (EAs). PySCF implements the G0W0 approximation, in which the self-energy is built with mean-field orbitals and orbital energies. Therefore, the results depend on the mean-field starting point, which can be Hartree-Fock or density functional theory. As described below, PySCF has three implementations of the GW approximation, all of which are “full-frequency”.

An example GW calculation is shown below:

#!/usr/bin/env python

'''
A simple example to run a GW calculation 
'''

from pyscf import gto, dft, gw
mol = gto.M(
    atom = 'H 0 0 0; F 0 0 1.1',
    basis = 'ccpvdz')
mf = dft.RKS(mol)
mf.xc = 'pbe'
mf.kernel()

nocc = mol.nelectron//2

# By default, GW is done with analytic continuation
gw = gw.GW(mf)
# same as gw = gw.GW(mf, freq_int='ac')
gw.kernel(orbs=range(nocc-3,nocc+3))
print(gw.mo_energy)

In this example, the orbs keyword argument is provided to select which GW orbital energies are requested. By default, all orbital energies (occupied and unoccupied) will be calculated, which will increase the cost and may have errors, depending on the method of frequency integration.

Frequency integration

The frequency integration needed for the GW approximation can be done in three ways, controlled by the freq_int keyword argument: by analytic continuation (AC, freq_int='ac'), contour deformation (CD, freq_int='cd'), or exactly (Exact, freq_int='exact'). The first two are much more affordable and typically provide sufficient accuracy. GW-AC supports spin-restricted and spin-unrestricted calculations; GW-CD and GW-Exact only support spin-restricted calculations. Details of the GW-AC and GW-CD implementations in PySCF can be found in Ref. [30].

Analytic continuation

Integration via analytic continuation is implemented in the GWAC module that is accessed with freq_int='ac', which is also the default GW module. GW-AC has \(N^4\) scaling and is recommended for valence states only. The analytic continuation can be done using a Pade approximation (default, more reliable) or a two-pole model, controlled by the ac attribute. GW-AC supports frozen core orbitals for reducing computational cost, controlled by the frozen attribute (number of frozen core MOs neglected in GW-AC calculation). Frozen core orbitals are not supported by other GW methods currently. There are two ways to compute GW orbital energies, controlled by the linearized attribute: linearized=False (default) solves the quasiparticle equation through a Newton solver self-consistently, while linearized=True employs a linearization approximation:

mygw = gw.GW(mf) # same as freq_int='ac' or GWAC module
# mygw.ac = 'pade' # default
mygw.ac = 'twopole'
mygw.frozen = 1 # default is None
mygw.linearized = False # default
mygw.kernel(orbs=range(nocc-3,nocc+3))

Contour deformation

Integration via contour deformation is implemented in the GWCD module that is accessed with freq_int='cd'. GW-CD has \(N^4\) scaling and is slower, but more robust, than GW-AC. GW-CD is particularly recommended for accurate core and high-energy states:

mygw = gw.GW(mf, freq_int='cd').run(orbs=[0,1])

Exact

Exact frequency integration can be carried out analytically and is implemented in the GWExact module that is accessed with freq_int='exact'. Exact integration requires complete diagonalization of the RPA matrix, which has \(N^6\) scaling. However, all orbital energies can be readily obtained without error:

mygw = gw.GW(mf, freq_int='exact').run()

By default, GW-Exact, like the other GW implementations, use the direct random-phase approximation (dRPA) to screen the Coulomb interaction. Within GW-Exact, any alternative time-dependent mean-field theory (TDHF, TDDFT, etc.) can be also used. The instance of an executed tdscf method can be provided as a keyword argument:

#!/usr/bin/env python

'''
GW calculation with exact frequency integration
and TDDFT screening instead of dRPA
'''

from pyscf import gto, dft, gw
mol = gto.M(
    atom = 'H 0 0 0; F 0 0 1.1',
    basis = 'ccpvdz')
mf = dft.RKS(mol)
mf.xc = 'pbe'
mf.kernel()

from pyscf import tdscf
nocc = mol.nelectron//2
nmo = mf.mo_energy.size
nvir = nmo-nocc
td = tdscf.TDDFT(mf)
td.nstates = nocc*nvir
td.verbose = 0
td.kernel()

gw = gw.GW(mf, freq_int='exact', tdmf=td)
gw.kernel()
print(gw.mo_energy)