def __init__(self, calc, gwfile, filename=None, kpts=[0], bands=None, structure=None, d=None, layer=0, dW_qw=None, qqeh=None, wqeh=None, txt=sys.stdout, world=mpi.world, domega0=0.025, omega2=10.0, eta=0.1, include_q0=True, metal=False): """ Class for calculating quasiparticle energies of van der Waals heterostructures using the GW approximation for the self-energy. The quasiparticle energy correction due to increased screening from surrounding layers is obtained from the QEH model. Parameters: calc: str or PAW object GPAW calculator object or filename of saved calculator object. gwfile: str name of gw results file from the monolayer calculation filename: str filename for gwqeh output kpts: list List of indices of sthe IBZ k-points to calculate the quasi particle energies for. Set to [0] by default since the QP correction is generally the same for all k. bands: tuple Range of band indices, like (n1, n2+1), to calculate the quasi particle energies for. Note that the second band index is not included. Should be the same as used for the GW calculation. structure: list of str Heterostructure set up. Each entry should consist of number of layers + chemical formula. For example: ['3H-MoS2', graphene', '10H-WS2'] gives 3 layers of H-MoS2, 1 layer of graphene and 10 layers of H-WS2. The name of the layers should correspond to building block files: "<name>-chi.pckl" in the local repository. d: array of floats Interlayer distances for neighboring layers in Ang. Length of array = number of layers - 1 layer: int index of layer to calculate QP correction for. dW_qw: 2D array of floats dimension q X w Change in screened interaction. Should be set to None to calculate dW directly from buildingblocks. qqeh: array of floats q-grid used for dW_qw (only needed if dW is given by hand). wqeh: array of floats w-grid used for dW_qw. So far this have to be the same as for the GWQEH calculation. (only needed if dW is given by hand). domega0: float Minimum frequency step (in eV) used in the generation of the non- linear frequency grid. omega2: float Control parameter for the non-linear frequency grid, equal to the frequency where the grid spacing has doubled in size. eta: float Broadening parameter. include_q0: bool include q=0 in W or not. if True an integral arround q=0 is performed, if False the q=0 contribution is set to zero. metal: bool If True, the point at q=0 is omitted when averaging the screened potential close to q=0. """ self.gwfile = gwfile self.inputcalc = calc # Set low ecut in order to use PairDensity object since only # G=0 is needed. self.ecut = 1. PairDensity.__init__(self, calc, ecut=self.ecut, world=world, txt=filename + '.txt') self.filename = filename self.ecut /= Hartree self.eta = eta / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree self.kpts = list(select_kpts(kpts, self.calc)) if bands is None: bands = [0, self.nocc2] self.bands = bands b1, b2 = bands self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1) self.eps_sin = np.empty(shape) # KS-eigenvalues self.f_sin = np.empty(shape) # occupation numbers self.sigma_sin = np.zeros(shape) # self-energies self.dsigma_sin = np.zeros(shape) # derivatives of self-energies self.Z_sin = None # renormalization factors self.qp_sin = None self.Qp_sin = None self.ecutnb = 150 / Hartree vol = abs(np.linalg.det(self.calc.wfs.gd.cell_cv)) self.vol = vol self.nbands = min(self.calc.get_number_of_bands(), int(vol * (self.ecutnb)**1.5 * 2**0.5 / 3 / pi**2)) self.nspins = self.calc.wfs.nspins kd = self.calc.wfs.kd self.mysKn1n2 = None # my (s, K, n1, n2) indices self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts]) # Find q-vectors and weights in the IBZ: assert -1 not in kd.bz2bz_ks offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c bzq_qc = monkhorst_pack(kd.N_c) + offset_c self.qd = KPointDescriptor(bzq_qc) self.qd.set_symmetry(self.calc.atoms, kd.symmetry) # frequency grid omax = self.find_maximum_frequency() self.omega_w = frequency_grid(self.domega0, self.omega2, omax) self.nw = len(self.omega_w) self.wsize = 2 * self.nw # Calculate screened potential of Heterostructure if dW_qw is None: try: self.qqeh, self.wqeh, dW_qw = pickle.load( open(filename + '_dW_qw.pckl', 'rb')) except: dW_qw = self.calculate_W_QEH(structure, d, layer) else: self.qqeh = qqeh self.wqeh = None # wqeh self.dW_qw = self.get_W_on_grid(dW_qw, include_q0=include_q0, metal=metal) assert self.nw == self.dW_qw.shape[1], \ ('Frequency grids doesnt match!') self.htp = HilbertTransform(self.omega_w, self.eta, gw=True) self.htm = HilbertTransform(self.omega_w, -self.eta, gw=True) self.complete = False self.nq = 0 if self.load_state_file(): if self.complete: print('Self-energy loaded from file', file=self.fd)
def __init__(self, calc, filename='gw', kpts=None, bands=None, nbands=None, ppa=False, wstc=False, ecut=150.0, eta=0.1, E0=1.0 * Hartree, domega0=0.025, omega2=10.0, world=mpi.world): PairDensity.__init__(self, calc, ecut, world=world, txt=filename + '.txt') self.filename = filename ecut /= Hartree self.ppa = ppa self.wstc = wstc self.eta = eta / Hartree self.E0 = E0 / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree print(' ___ _ _ _ ', file=self.fd) print(' | || | | |', file=self.fd) print(' | | || | | |', file=self.fd) print(' |__ ||_____|', file=self.fd) print(' |___| ', file=self.fd) print(file=self.fd) self.kpts = select_kpts(kpts, self.calc) if bands is None: bands = [0, self.nocc2] self.bands = bands b1, b2 = bands self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1) self.eps_sin = np.empty(shape) # KS-eigenvalues self.f_sin = np.empty(shape) # occupation numbers self.sigma_sin = np.zeros(shape) # self-energies self.dsigma_sin = np.zeros(shape) # derivatives of self-energies self.vxc_sin = None # KS XC-contributions self.exx_sin = None # exact exchange contributions self.Z_sin = None # renormalization factors if nbands is None: nbands = int(self.vol * ecut**1.5 * 2**0.5 / 3 / pi**2) self.nbands = nbands kd = self.calc.wfs.kd self.mysKn1n2 = None # my (s, K, n1, n2) indices self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts]) # Find q-vectors and weights in the IBZ: assert -1 not in kd.bz2bz_ks offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c bzq_qc = monkhorst_pack(kd.N_c) + offset_c self.qd = KPointDescriptor(bzq_qc) self.qd.set_symmetry(self.calc.atoms, self.calc.wfs.setups, usesymm=self.calc.input_parameters.usesymm, N_c=self.calc.wfs.gd.N_c) assert self.calc.wfs.nspins == 1
def __init__(self, calc, filename='gw', kpts=None, bands=None, nbands=None, ppa=False, wstc=False, ecut=150.0, eta=0.1, E0=1.0 * Hartree, domega0=0.025, omega2=10.0, nblocks=1, savew=False, world=mpi.world): if world.rank != 0: txt = devnull else: txt = open(filename + '.txt', 'w') p = functools.partial(print, file=txt) p(' ___ _ _ _ ') p(' | || | | |') p(' | | || | | |') p(' |__ ||_____|') p(' |___|') p() PairDensity.__init__(self, calc, ecut, world=world, nblocks=nblocks, txt=txt) self.filename = filename self.savew = savew ecut /= Hartree self.ppa = ppa self.wstc = wstc self.eta = eta / Hartree self.E0 = E0 / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree self.kpts = select_kpts(kpts, self.calc) if bands is None: bands = [0, self.nocc2] self.bands = bands b1, b2 = bands self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1) self.eps_sin = np.empty(shape) # KS-eigenvalues self.f_sin = np.empty(shape) # occupation numbers self.sigma_sin = np.zeros(shape) # self-energies self.dsigma_sin = np.zeros(shape) # derivatives of self-energies self.vxc_sin = None # KS XC-contributions self.exx_sin = None # exact exchange contributions self.Z_sin = None # renormalization factors if nbands is None: nbands = int(self.vol * ecut**1.5 * 2**0.5 / 3 / pi**2) self.nbands = nbands p() p('Quasi particle states:') if kpts is None: p('All k-points in IBZ') else: kptstxt = ', '.join(['{0:d}'.format(k) for k in self.kpts]) p('k-points (IBZ indices): [' + kptstxt + ']') p('Band range: ({0:d}, {1:d})'.format(b1, b2)) p() p('Computational parameters:') p('Plane wave cut-off: {0:g} eV'.format(self.ecut * Hartree)) p('Number of bands: {0:d}'.format(self.nbands)) p('Broadening: {0:g} eV'.format(self.eta * Hartree)) kd = self.calc.wfs.kd self.mysKn1n2 = None # my (s, K, n1, n2) indices self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts]) # Find q-vectors and weights in the IBZ: assert -1 not in kd.bz2bz_ks offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c bzq_qc = monkhorst_pack(kd.N_c) + offset_c self.qd = KPointDescriptor(bzq_qc) self.qd.set_symmetry(self.calc.atoms, kd.symmetry) assert self.calc.wfs.nspins == 1