def get_phi_aGp(self, q_c=None, parallel=True, alldir=False): if q_c is None: q_c = self.q_c qq_v = self.qq_v optical_limit = self.optical_limit else: optical_limit = False if np.abs(q_c).sum() < 1e-8: q_c = np.array([0.0001, 0, 0]) optical_limit = True qq_v = np.dot(q_c, self.bcell_cv) setups = self.calc.wfs.setups spos_ac = self.calc.atoms.get_scaled_positions() kk_Gv = gemmdot(q_c + self.Gvec_Gc, self.bcell_cv.copy(), beta=0.0) phi_aGp = {} phiG0_avp = {} if parallel: from gpaw.response.parallel import parallel_partition npw, npw_local, Gstart, Gend = parallel_partition(self.npw, self.comm.rank, self.comm.size, reshape=False) else: Gstart = 0 Gend = self.npw for a, id in enumerate(setups.id_a): phi_aGp[a] = two_phi_planewave_integrals(kk_Gv, setups[a], Gstart, Gend) for iG in range(Gstart, Gend): phi_aGp[a][iG] *= np.exp( -1j * 2. * pi * np.dot(q_c + self.Gvec_Gc[iG], spos_ac[a])) if parallel: self.comm.sum(phi_aGp[a]) # For optical limit, G == 0 part should change if optical_limit: for a, id in enumerate(setups.id_a): nabla_iiv = setups[a].nabla_iiv phi_aGp[a][0] = -1j * (np.dot(nabla_iiv, qq_v)).ravel() phiG0_avp[a] = np.zeros((3, len(phi_aGp[a][0])), complex) for dir in range(3): # 3 dimension q2_c = np.diag((1, 1, 1))[dir] * self.qopt qq2_v = np.dot(q2_c, self.bcell_cv) # summation over c phiG0_avp[a][dir] = -1j * (np.dot(nabla_iiv, qq2_v)).ravel() if alldir: return phi_aGp, phiG0_avp else: return phi_aGp
def get_phi_aGp(self, q_c=None, parallel=True, alldir=False): if q_c is None: q_c = self.q_c qq_v = self.qq_v optical_limit = self.optical_limit else: optical_limit = False if np.abs(q_c).sum() < 1e-8: q_c = np.array([0.0001, 0, 0]) optical_limit = True qq_v = np.dot(q_c, self.bcell_cv) setups = self.calc.wfs.setups spos_ac = self.calc.atoms.get_scaled_positions() kk_Gv = gemmdot(q_c + self.Gvec_Gc, self.bcell_cv.copy(), beta=0.0) phi_aGp = {} phiG0_avp = {} if parallel: from gpaw.response.parallel import parallel_partition npw, npw_local, Gstart, Gend = parallel_partition( self.npw, self.comm.rank, self.comm.size, reshape=False) else: Gstart = 0 Gend = self.npw for a, id in enumerate(setups.id_a): phi_aGp[a] = two_phi_planewave_integrals(kk_Gv, setups[a], Gstart, Gend) for iG in range(Gstart, Gend): phi_aGp[a][iG] *= np.exp(-1j * 2. * pi * np.dot(q_c + self.Gvec_Gc[iG], spos_ac[a]) ) if parallel: self.comm.sum(phi_aGp[a]) # For optical limit, G == 0 part should change if optical_limit: for a, id in enumerate(setups.id_a): nabla_iiv = setups[a].nabla_iiv phi_aGp[a][0] = -1j * (np.dot(nabla_iiv, qq_v)).ravel() phiG0_avp[a] = np.zeros((3, len(phi_aGp[a][0])), complex) for dir in range(3): # 3 dimension q2_c = np.diag((1,1,1))[dir] * self.qopt qq2_v = np.dot(q2_c, self.bcell_cv) # summation over c phiG0_avp[a][dir] = -1j * (np.dot(nabla_iiv, qq2_v)).ravel() if alldir: return phi_aGp, phiG0_avp else: return phi_aGp
def initialize(self): self.printtxt('') self.printtxt('-----------------------------------------------') self.printtxt('Belth Selpeter Equation calculation started at:') self.printtxt(ctime()) BASECHI.initialize(self) calc = self.calc self.kd = kd = calc.wfs.kd # frequency points init self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.Nw = int(self.wmax / self.dw) + 1 # find the pair index and initialized pair energy (e_i - e_j) and occupation(f_i-f_j) self.e_S = {} focc_s = {} self.Sindex_S3 = {} iS = 0 kq_k = self.kq_k for k1 in range(self.nkpt): ibzkpt1 = kd.kibz_k[k1] ibzkpt2 = kd.kibz_k[kq_k[k1]] for n1 in range(self.nbands): for m1 in range(self.nbands): focc = self.f_kn[ibzkpt1, n1] - self.f_kn[ibzkpt2, m1] if np.abs(focc) > self.ftol: self.e_S[iS] = self.e_kn[ibzkpt2, m1] - self.e_kn[ibzkpt1, n1] focc_s[iS] = focc self.Sindex_S3[iS] = (k1, n1, m1) iS += 1 self.nS = iS self.focc_S = np.zeros(self.nS) for iS in range(self.nS): self.focc_S[iS] = focc_s[iS] # parallel init self.Scomm = world # kcomm and wScomm is only to be used when wavefunctions r parallelly distributed. self.kcomm = world self.wScomm = serial_comm self.nS, self.nS_local, self.nS_start, self.nS_end = parallel_partition( self.nS, self.Scomm.rank, self.Scomm.size, reshape=False) self.print_bse() self.get_phi_aGp() # Coulomb kernel init self.kc_G = np.zeros(self.npw) for iG in range(self.npw): index = self.Gindex_G[iG] qG = np.dot(self.q_c + self.Gvec_Gc[iG], self.bcell_cv) self.kc_G[iG] = 1. / np.inner(qG, qG) if self.optical_limit: self.kc_G[0] = 0. self.printtxt('') return
def initialize(self): self.ini = True BASECHI.initialize(self) self.txtname = self.gwtxtname self.output_init() self.printtxt('GPAW version %s' % (version)) self.printtxt('-----------------------------------------------') self.printtxt('GW calculation started at:') self.printtxt(ctime()) self.printtxt('-----------------------------------------------') self.starttime = time() calc = self.calc kd = self.kd # band init if self.gwnbands is None: if self.npw > calc.wfs.bd.nbands: self.nbands = calc.wfs.bd.nbands else: self.nbands = self.npw # eigenvalue init if self.user_skn is not None: self.printtxt('Use eigenvalues from user.') assert np.shape( self.user_skn )[0] == self.nspins, 'Eigenvalues not compatible with .gpw file!' assert np.shape( self.user_skn )[1] == self.kd.nibzkpts, 'Eigenvalues not compatible with .gpw file!' assert np.shape( self.user_skn)[2] >= self.nbands, 'Too few eigenvalues!' self.e_skn = self.user_skn else: self.printtxt('Use eigenvalues from the calculator.') # q point init self.bzq_kc = kd.get_bz_q_points() self.ibzq_qc = self.bzq_kc # q point symmetry is not used at the moment. self.nqpt = np.shape(self.bzq_kc)[0] # frequency points init self.static = False if self.ppa: # Plasmon Pole Approximation if self.E0 is None: self.E0 = Hartree self.E0 /= Hartree self.w_w = np.array([0., 1j * self.E0]) self.hilbert_trans = False self.wpar = 1 elif self.w_w is None: # static COHSEX self.w_w = np.array([0.]) self.static = True self.hilbert_trans = False self.wpar = 1 self.eta = 0.0001 / Hartree else: # create nonlinear frequency grid # grid is linear from 0 to wcut with spacing dw # spacing is linearily increasing between wcut and wmax # Hilbert transforms are still carried out on linear grid wcut = self.w_w[0] wmax = self.w_w[1] dw = self.w_w[2] w_w = np.linspace(0., wcut, wcut / dw + 1) i = 1 wi = wcut while wi < wmax: wi += i * dw w_w = np.append(w_w, wi) i += 1 while len(w_w) % self.wpar != 0: wi += i * dw w_w = np.append(w_w, wi) i += 1 dw_w = np.zeros(len(w_w)) dw_w[0] = dw dw_w[1:] = w_w[1:] - w_w[:-1] self.w_w = w_w / Hartree self.dw_w = dw_w / Hartree self.eta_w = dw_w * 4 / Hartree self.wcut = wcut self.wmax = self.w_w[-1] self.wmin = self.w_w[0] self.dw = self.w_w[1] - self.w_w[0] self.Nw = len(self.w_w) # self.wpar = int(self.Nw * self.npw**2 * 16. / 1024**2) // 1500 + 1 # estimate memory and parallelize over frequencies for s in range(self.nspins): emaxdiff = self.e_skn[s][:, self.nbands - 1].max() - self.e_skn[s][:, 0].min() assert (self.wmax > emaxdiff ), 'Maximum frequency must be larger than %f' % ( emaxdiff * Hartree) # GW kpoints init if self.kpoints is None: self.gwnkpt = self.kd.nibzkpts self.gwkpt_k = kd.ibz2bz_k else: self.gwnkpt = np.shape(self.kpoints)[0] self.gwkpt_k = self.kpoints # GW bands init if self.bands is None: self.gwnband = self.nbands self.bands = self.gwbands_n = np.arange(self.nbands) else: self.gwnband = np.shape(self.bands)[0] self.gwbands_n = self.bands self.alpha = 1j / (2 * pi * self.vol * self.kd.nbzkpts) # parallel init assert len(self.w_w) % self.wpar == 0 self.wcommsize = self.wpar self.qcommsize = size // self.wpar assert self.qcommsize * self.wcommsize == size, 'wpar must be integer divisor of number of requested cores' if self.nqpt != 1: # parallelize over q-points self.wcomm, self.qcomm, self.worldcomm = set_communicator( world, rank, size, self.wpar) self.ncomm = serial_comm self.dfcomm = self.wcomm self.kcommsize = 1 else: # parallelize over bands self.wcomm, self.ncomm, self.worldcomm = set_communicator( world, rank, size, self.wpar) self.qcomm = serial_comm if self.wpar > 1: self.dfcomm = self.wcomm self.kcommsize = 1 else: self.dfcomm = self.ncomm self.kcommsize = self.ncomm.size nq, self.nq_local, self.q_start, self.q_end = parallel_partition( self.nqpt, self.qcomm.rank, self.qcomm.size, reshape=False) nb, self.nbands_local, self.m_start, self.m_end = parallel_partition( self.nbands, self.ncomm.rank, self.ncomm.size, reshape=False)
def parallel_init(self): """Parallel initialization. By default, only use kcomm and wcomm. Parameters: kcomm: kpoint communicator wScomm: spectral function communicator wcomm: frequency communicator """ if extra_parameters.get("df_dry_run"): from gpaw.mpi import DryRunCommunicator size = extra_parameters["df_dry_run"] world = DryRunCommunicator(size) rank = world.rank self.comm = world else: world = self.comm rank = self.comm.rank size = self.comm.size wcommsize = int(self.NwS * self.npw ** 2 * 16.0 / 1024 ** 2) // 1500 # megabyte wcommsize += 1 if size < wcommsize: raise ValueError("Number of cpus are not enough ! ") if self.kcommsize is None: self.kcommsize = world.size if wcommsize > size // self.kcommsize: # if matrix too large, overwrite kcommsize and distribute matrix self.printtxt("kcommsize is over written ! ") while size % wcommsize != 0: wcommsize += 1 self.kcommsize = size // wcommsize assert self.kcommsize * wcommsize == size if self.kcommsize < 1: raise ValueError("Number of cpus are not enough ! ") self.kcomm, self.wScomm, self.wcomm = set_communicator(world, rank, size, self.kcommsize) if self.kd.nbzkpts >= world.size: self.nkpt_reshape = self.kd.nbzkpts self.nkpt_reshape, self.nkpt_local, self.kstart, self.kend = parallel_partition( self.nkpt_reshape, self.kcomm.rank, self.kcomm.size, reshape=True, positive=True ) self.mband_local = self.nvalbands self.mlist = np.arange(self.nbands) else: # if number of kpoints == 1, use band parallelization self.nkpt_local = self.kd.nbzkpts self.kstart = 0 self.kend = self.kd.nbzkpts self.nkpt_reshape = self.kd.nbzkpts self.nbands, self.mband_local, self.mlist = parallel_partition_list( self.nbands, self.kcomm.rank, self.kcomm.size ) if self.NwS % size != 0: self.NwS -= self.NwS % size self.NwS, self.NwS_local, self.wS1, self.wS2 = parallel_partition( self.NwS, self.wScomm.rank, self.wScomm.size, reshape=False ) if self.hilbert_trans: self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=True ) else: if self.Nw > 1: # assert self.Nw % (self.comm.size / self.kcomm.size) == 0 self.wcomm = self.wScomm self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=False ) else: # if frequency point is too few, then dont parallelize self.wcomm = serial_comm self.wstart = 0 self.wend = self.Nw self.Nw_local = self.Nw return
def initialize(self): self.ini = True BASECHI.initialize(self) self.txtname = self.gwtxtname self.output_init() self.printtxt('GPAW version %s' %(version)) self.printtxt('-----------------------------------------------') self.printtxt('GW calculation started at:') self.printtxt(ctime()) self.printtxt('-----------------------------------------------') self.starttime = time() calc = self.calc kd = self.kd # band init if self.gwnbands is None: if self.npw > calc.wfs.bd.nbands: self.nbands = calc.wfs.bd.nbands else: self.nbands = self.npw # eigenvalue init if self.user_skn is not None: self.printtxt('Use eigenvalues from user.') assert np.shape(self.user_skn)[0] == self.nspins, 'Eigenvalues not compatible with .gpw file!' assert np.shape(self.user_skn)[1] == self.kd.nibzkpts, 'Eigenvalues not compatible with .gpw file!' assert np.shape(self.user_skn)[2] >= self.nbands, 'Too few eigenvalues!' self.e_skn = self.user_skn else: self.printtxt('Use eigenvalues from the calculator.') # q point init self.bzq_kc = kd.get_bz_q_points() self.ibzq_qc = self.bzq_kc # q point symmetry is not used at the moment. self.nqpt = np.shape(self.bzq_kc)[0] # frequency points init self.static=False if self.ppa: # Plasmon Pole Approximation if self.E0 is None: self.E0 = Hartree self.E0 /= Hartree self.w_w = np.array([0., 1j*self.E0]) self.hilbert_trans=False self.wpar=1 elif self.w_w is None: # static COHSEX self.w_w = np.array([0.]) self.static=True self.hilbert_trans=False self.wpar=1 self.eta = 0.0001 / Hartree else: # create nonlinear frequency grid # grid is linear from 0 to wcut with spacing dw # spacing is linearily increasing between wcut and wmax # Hilbert transforms are still carried out on linear grid wcut = self.w_w[0] wmax = self.w_w[1] dw = self.w_w[2] w_w = np.linspace(0., wcut, wcut/dw+1) i=1 wi=wcut while wi < wmax: wi += i*dw w_w = np.append(w_w, wi) i+=1 while len(w_w) % self.wpar != 0: wi += i*dw w_w = np.append(w_w, wi) i+=1 dw_w = np.zeros(len(w_w)) dw_w[0] = dw dw_w[1:] = w_w[1:] - w_w[:-1] self.w_w = w_w / Hartree self.dw_w = dw_w / Hartree self.eta_w = dw_w * 4 / Hartree self.wcut = wcut self.wmax = self.w_w[-1] self.wmin = self.w_w[0] self.dw = self.w_w[1] - self.w_w[0] self.Nw = len(self.w_w) # self.wpar = int(self.Nw * self.npw**2 * 16. / 1024**2) // 1500 + 1 # estimate memory and parallelize over frequencies for s in range(self.nspins): emaxdiff = self.e_skn[s][:,self.nbands-1].max() - self.e_skn[s][:,0].min() assert (self.wmax > emaxdiff), 'Maximum frequency must be larger than %f' %(emaxdiff*Hartree) # GW kpoints init if self.kpoints is None: self.gwnkpt = self.kd.nibzkpts self.gwkpt_k = kd.ibz2bz_k else: self.gwnkpt = np.shape(self.kpoints)[0] self.gwkpt_k = self.kpoints # GW bands init if self.bands is None: self.gwnband = self.nbands self.bands = self.gwbands_n = np.arange(self.nbands) else: self.gwnband = np.shape(self.bands)[0] self.gwbands_n = self.bands self.alpha = 1j/(2*pi * self.vol * self.kd.nbzkpts) # parallel init assert len(self.w_w) % self.wpar == 0 self.wcommsize = self.wpar self.qcommsize = size // self.wpar assert self.qcommsize * self.wcommsize == size, 'wpar must be integer divisor of number of requested cores' if self.nqpt != 1: # parallelize over q-points self.wcomm, self.qcomm, self.worldcomm = set_communicator(world, rank, size, self.wpar) self.ncomm = serial_comm self.dfcomm = self.wcomm self.kcommsize = 1 else: # parallelize over bands self.wcomm, self.ncomm, self.worldcomm = set_communicator(world, rank, size, self.wpar) self.qcomm = serial_comm if self.wpar > 1: self.dfcomm = self.wcomm self.kcommsize = 1 else: self.dfcomm = self.ncomm self.kcommsize = self.ncomm.size nq, self.nq_local, self.q_start, self.q_end = parallel_partition( self.nqpt, self.qcomm.rank, self.qcomm.size, reshape=False) nb, self.nbands_local, self.m_start, self.m_end = parallel_partition( self.nbands, self.ncomm.rank, self.ncomm.size, reshape=False)
def parallel_init(self): """Parallel initialization. By default, only use kcomm and wcomm. Parameters: kcomm: kpoint communicator wScomm: spectral function communicator wcomm: frequency communicator """ if extra_parameters.get('df_dry_run'): from gpaw.mpi import DryRunCommunicator size = extra_parameters['df_dry_run'] world = DryRunCommunicator(size) rank = world.rank self.comm = world else: world = self.comm rank = self.comm.rank size = self.comm.size wcommsize = int(self.NwS * self.npw**2 * 16. / 1024**2) // 1500 # megabyte wcommsize += 1 if size < wcommsize: raise ValueError('Number of cpus are not enough ! ') if self.kcommsize is None: self.kcommsize = world.size if wcommsize > size // self.kcommsize: # if matrix too large, overwrite kcommsize and distribute matrix self.printtxt('kcommsize is over written ! ') while size % wcommsize != 0: wcommsize += 1 self.kcommsize = size // wcommsize assert self.kcommsize * wcommsize == size if self.kcommsize < 1: raise ValueError('Number of cpus are not enough ! ') self.kcomm, self.wScomm, self.wcomm = set_communicator(world, rank, size, self.kcommsize) if self.kd.nbzkpts >= world.size: self.nkpt_reshape = self.kd.nbzkpts self.nkpt_reshape, self.nkpt_local, self.kstart, self.kend = parallel_partition( self.nkpt_reshape, self.kcomm.rank, self.kcomm.size, reshape=True, positive=True) self.mband_local = self.nvalbands self.mlist = np.arange(self.nbands) else: # if number of kpoints == 1, use band parallelization self.nkpt_local = self.kd.nbzkpts self.kstart = 0 self.kend = self.kd.nbzkpts self.nkpt_reshape = self.kd.nbzkpts self.nbands, self.mband_local, self.mlist = parallel_partition_list( self.nbands, self.kcomm.rank, self.kcomm.size) if self.NwS % size != 0: self.NwS -= self.NwS % size self.NwS, self.NwS_local, self.wS1, self.wS2 = parallel_partition( self.NwS, self.wScomm.rank, self.wScomm.size, reshape=False) if self.hilbert_trans: self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=True) else: if self.Nw > 1: # assert self.Nw % (self.comm.size / self.kcomm.size) == 0 self.wcomm = self.wScomm self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=False) else: # if frequency point is too few, then dont parallelize self.wcomm = serial_comm self.wstart = 0 self.wend = self.Nw self.Nw_local = self.Nw return
def initialize(self): self.printtxt('') self.printtxt('-----------------------------------------------') self.printtxt('Belth Selpeter Equation calculation started at:') self.printtxt(ctime()) BASECHI.initialize(self) calc = self.calc self.kd = kd = calc.wfs.kd # frequency points init self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.Nw = int(self.wmax / self.dw) + 1 # find the pair index and initialized pair energy (e_i - e_j) and occupation(f_i-f_j) self.e_S = {} focc_s = {} self.Sindex_S3 = {} iS = 0 kq_k = self.kq_k for k1 in range(self.nkpt): ibzkpt1 = kd.kibz_k[k1] ibzkpt2 = kd.kibz_k[kq_k[k1]] for n1 in range(self.nbands): for m1 in range(self.nbands): focc = self.f_kn[ibzkpt1,n1] - self.f_kn[ibzkpt2,m1] if np.abs(focc) > self.ftol: self.e_S[iS] =self.e_kn[ibzkpt2,m1] - self.e_kn[ibzkpt1,n1] focc_s[iS] = focc self.Sindex_S3[iS] = (k1, n1, m1) iS += 1 self.nS = iS self.focc_S = np.zeros(self.nS) for iS in range(self.nS): self.focc_S[iS] = focc_s[iS] # parallel init self.Scomm = world # kcomm and wScomm is only to be used when wavefunctions r parallelly distributed. self.kcomm = world self.wScomm = serial_comm self.nS, self.nS_local, self.nS_start, self.nS_end = parallel_partition( self.nS, self.Scomm.rank, self.Scomm.size, reshape=False) self.print_bse() self.get_phi_aGp() # Coulomb kernel init self.kc_G = np.zeros(self.npw) for iG in range(self.npw): index = self.Gindex_G[iG] qG = np.dot(self.q_c + self.Gvec_Gc[iG], self.bcell_cv) self.kc_G[iG] = 1. / np.inner(qG, qG) if self.optical_limit: self.kc_G[0] = 0. self.printtxt('') return
def initialize(self): self.printtxt('----------------------------------------') self.printtxt('Bethe-Salpeter Equation calculation') self.printtxt('----------------------------------------') self.printtxt('Started at: %s' % ctime()) self.printtxt('') BASECHI.initialize(self) assert self.nspins == 1 calc = self.calc self.kd = kd = calc.wfs.kd # frequency points init self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.Nw = int(self.wmax / self.dw) + 1 # band init if self.nc is None: nv = self.nvalence / 2 - 1 self.nv = np.array([nv, nv+1]) # conduction band start / end self.nc = np.array([nv+1, nv+2]) # valence band start / end self.printtxt('') self.printtxt('Number of electrons : %d' % (self.nvalence)) self.printtxt('Valence band included : (band %d to band %d)' %(self.nv[0], self.nv[1]-1)) self.printtxt('Conduction band included : (band %d to band %d)' %(self.nc[0], self.nc[1]-1)) if self.eshift is not None: self.printtxt('Scissors operator : %2.3f eV' % self.eshift) self.printtxt('') # find the pair index and initialized pair energy (e_i - e_j) and occupation(f_i-f_j) self.e_S = {} focc_s = {} self.Sindex_S3 = {} iS = 0 kq_k = self.kq_k for k1 in range(self.kd.nbzkpts): ibzkpt1 = kd.bz2ibz_k[k1] ibzkpt2 = kd.bz2ibz_k[kq_k[k1]] for n1 in range(self.nv[0], self.nv[1]): for m1 in range(self.nc[0], self.nc[1]): focc = self.f_skn[0][ibzkpt1,n1] - self.f_skn[0][ibzkpt2,m1] if self.coupling: # Dont use Tamm-Dancoff Approx. check_ftol = np.abs(focc) > self.ftol else: check_ftol = focc > self.ftol if check_ftol: if self.gw_skn is None: self.e_S[iS] = self.e_skn[0][ibzkpt2,m1] - self.e_skn[0][ibzkpt1,n1] else: self.e_S[iS] = self.gw_skn[0][ibzkpt2,m1] - self.gw_skn[0][ibzkpt1,n1] focc_s[iS] = focc self.Sindex_S3[iS] = (k1, n1, m1) iS += 1 self.nS = iS self.focc_S = np.zeros(self.nS) for iS in range(self.nS): self.focc_S[iS] = focc_s[iS] # q points init self.bzq_qc = kd.get_bz_q_points() if not self.qsymm: self.ibzq_qc = self.bzq_qc else: (self.ibzq_qc, self.ibzq_q, self.iop_q, self.timerev_q, self.diff_qc) = kd.get_ibz_q_points(self.bzq_qc, calc.wfs.symmetry.op_scc) if np.abs(self.bzq_qc - kd.bzk_kc).sum() < 1e-8: assert np.abs(self.ibzq_qc - kd.ibzk_kc).sum() < 1e-8 self.nibzq = len(self.ibzq_qc) # Parallel initialization # kcomm and wScomm is only to be used when wavefunctions are distributed in parallel. self.comm = self.Scomm = world self.kcomm = world self.wScomm = serial_comm self.nS, self.nS_local, self.nS_start, self.nS_end = parallel_partition( self.nS, world.rank, world.size, reshape=False) self.print_bse() if calc.input_parameters['mode'] == 'lcao': calc.initialize_positions() # Coulomb interaction at q=0 for Hartree coupling ### 2D z direction only !!!!!!!!!!!!!!!!!!!!!! if self.integrate_coulomb is None: self.integrate_coulomb = [] if self.vcut is None: pass elif self.vcut == '2D': for iG in range(len(self.Gvec_Gc)): if self.Gvec_Gc[iG, 0] == 0 and self.Gvec_Gc[iG, 1] == 0: self.integrate_coulomb.append(iG) else: raise NotImplementedError elif type(self.integrate_coulomb) is int: self.integrate_coulomb = range(self.integrate_coulomb) elif self.integrate_coulomb == 'all': self.integrate_coulomb = range(len(self.Gvec_Gc)) elif type(self.integrate_coulomb) is list: pass else: raise 'Invalid option for integrate_coulomb' self.printtxt('') self.printtxt('Calculating bare Coulomb kernel') if not len(self.integrate_coulomb) == 0: self.printtxt('Integrating Coulomb kernel at %s reciprocal lattice vector(s)' % len(self.integrate_coulomb)) # Coulomb interaction at problematic G's for exchange coupling if len(self.integrate_coulomb) != 0: self.vint_Gq = [] for iG in self.integrate_coulomb: v_q, v0_q = calculate_Kc_q(self.acell_cv, self.bcell_cv, self.pbc, self.kd.N_c, vcut=self.vcut, Gvec_c=self.Gvec_Gc[iG], q_qc=self.ibzq_qc.copy()) self.vint_Gq.append(v_q) if self.print_coulomb: self.printtxt('') self.printtxt('Average kernel relative to bare kernel - \int v(q)dq / v(q0): ') self.printtxt(' G: % s' % self.Gvec_Gc[iG]) for iq in range(len(v_q)): q_s = ' q = [%1.2f, %1.2f, %1.2f]: ' % (self.ibzq_qc[iq,0], self.ibzq_qc[iq,1], self.ibzq_qc[iq,2]) v_rel = v_q[iq] / v0_q[iq] self.printtxt(q_s + '%1.3f' % v_rel) self.printtxt('') self.V_qGG = self.full_bare_interaction() return
def get_phi_qaGp(self): N1_max = 0 N2_max = 0 natoms = len(self.calc.wfs.setups) for id in range(natoms): N1 = self.npw N2 = self.calc.wfs.setups[id].ni**2 if N1 > N1_max: N1_max = N1 if N2 > N2_max: N2_max = N2 nbzq = self.kd.nbzkpts nbzq, nq_local, q_start, q_end = parallel_partition( nbzq, world.rank, world.size, reshape=False) phimax_qaGp = np.zeros((nq_local, natoms, N1_max, N2_max), dtype=complex) #phimax_qaGp = np.zeros((nbzq, natoms, N1_max, N2_max), dtype=complex) t0 = time() for iq in range(nq_local): q_c = self.bzq_qc[iq + q_start] tmp_aGp = self.get_phi_aGp(q_c, parallel=False) for id in range(natoms): N1, N2 = tmp_aGp[id].shape phimax_qaGp[iq, id, :N1, :N2] = tmp_aGp[id] self.timing(iq*world.size, t0, nq_local, 'iq') world.barrier() # Write to disk filename = 'phi_qaGp' if world.rank == 0: w = Writer(filename) w.dimension('nbzq', nbzq) w.dimension('natoms', natoms) w.dimension('nG', N1_max) w.dimension('nii', N2_max) w.add('phi_qaGp', ('nbzq', 'natoms', 'nG', 'nii',), dtype=complex) for q in range(nbzq): residual = nbzq % size N_local = nbzq // size if q < residual * (N_local + 1): qrank = q // (N_local + 1) else: qrank = (q - residual * (N_local + 1)) // N_local + residual if qrank == 0: if world.rank == 0: phi_aGp = phimax_qaGp[q - q_start] else: if world.rank == qrank: phi_aGp = phimax_qaGp[q - q_start] world.send(phi_aGp, 0, q) elif world.rank == 0: world.receive(phi_aGp, qrank, q) if world.rank == 0: w.fill(phi_aGp) world.barrier() if world.rank == 0: w.close() return
def initialize(self): self.printtxt('----------------------------------------') self.printtxt('Bethe-Salpeter Equation calculation') self.printtxt('----------------------------------------') self.printtxt('Started at: %s' % ctime()) self.printtxt('') BASECHI.initialize(self) assert self.nspins == 1 calc = self.calc self.kd = kd = calc.wfs.kd # frequency points init self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.Nw = int(self.wmax / self.dw) + 1 # band init if self.nc is None: nv = self.nvalence / 2 - 1 self.nv = np.array([nv, nv + 1]) # conduction band start / end self.nc = np.array([nv + 1, nv + 2]) # valence band start / end self.printtxt('') self.printtxt('Number of electrons : %d' % (self.nvalence)) self.printtxt('Valence band included : (band %d to band %d)' % (self.nv[0], self.nv[1] - 1)) self.printtxt('Conduction band included : (band %d to band %d)' % (self.nc[0], self.nc[1] - 1)) if self.eshift is not None: self.printtxt('Scissors operator : %2.3f eV' % self.eshift) self.printtxt('') # find the pair index and initialized pair energy (e_i - e_j) and occupation(f_i-f_j) self.e_S = {} focc_s = {} self.Sindex_S3 = {} iS = 0 kq_k = self.kq_k for k1 in range(self.kd.nbzkpts): ibzkpt1 = kd.bz2ibz_k[k1] ibzkpt2 = kd.bz2ibz_k[kq_k[k1]] for n1 in range(self.nv[0], self.nv[1]): for m1 in range(self.nc[0], self.nc[1]): focc = self.f_skn[0][ibzkpt1, n1] - self.f_skn[0][ibzkpt2, m1] if self.coupling: # Dont use Tamm-Dancoff Approx. check_ftol = np.abs(focc) > self.ftol else: check_ftol = focc > self.ftol if check_ftol: if self.gw_skn is None: self.e_S[iS] = self.e_skn[0][ ibzkpt2, m1] - self.e_skn[0][ibzkpt1, n1] else: self.e_S[iS] = self.gw_skn[0][ ibzkpt2, m1] - self.gw_skn[0][ibzkpt1, n1] focc_s[iS] = focc self.Sindex_S3[iS] = (k1, n1, m1) iS += 1 self.nS = iS self.focc_S = np.zeros(self.nS) for iS in range(self.nS): self.focc_S[iS] = focc_s[iS] # q points init self.bzq_qc = kd.get_bz_q_points() if not self.qsymm: self.ibzq_qc = self.bzq_qc else: (self.ibzq_qc, self.ibzq_q, self.iop_q, self.timerev_q, self.diff_qc) = kd.get_ibz_q_points(self.bzq_qc, calc.wfs.kd.symmetry.op_scc) if np.abs(self.bzq_qc - kd.bzk_kc).sum() < 1e-8: assert np.abs(self.ibzq_qc - kd.ibzk_kc).sum() < 1e-8 self.nibzq = len(self.ibzq_qc) # Parallel initialization # kcomm and wScomm is only to be used when wavefunctions are distributed in parallel. self.comm = self.Scomm = world self.kcomm = world self.wScomm = serial_comm self.nS, self.nS_local, self.nS_start, self.nS_end = parallel_partition( self.nS, world.rank, world.size, reshape=False) self.print_bse() if calc.input_parameters['mode'] == 'lcao': calc.initialize_positions() # Coulomb interaction at q=0 for Hartree coupling ### 2D z direction only !!!!!!!!!!!!!!!!!!!!!! if self.integrate_coulomb is None: self.integrate_coulomb = [] if self.vcut is None: pass elif self.vcut == '2D': for iG in range(len(self.Gvec_Gc)): if self.Gvec_Gc[iG, 0] == 0 and self.Gvec_Gc[iG, 1] == 0: self.integrate_coulomb.append(iG) else: raise NotImplementedError elif type(self.integrate_coulomb) is int: self.integrate_coulomb = range(self.integrate_coulomb) elif self.integrate_coulomb == 'all': self.integrate_coulomb = range(len(self.Gvec_Gc)) elif type(self.integrate_coulomb) is list: pass else: raise 'Invalid option for integrate_coulomb' self.printtxt('') self.printtxt('Calculating bare Coulomb kernel') if not len(self.integrate_coulomb) == 0: self.printtxt( 'Integrating Coulomb kernel at %s reciprocal lattice vector(s)' % len(self.integrate_coulomb)) # Coulomb interaction at problematic G's for exchange coupling if len(self.integrate_coulomb) != 0: self.vint_Gq = [] for iG in self.integrate_coulomb: v_q, v0_q = calculate_Kc_q(self.acell_cv, self.bcell_cv, self.pbc, self.kd.N_c, vcut=self.vcut, Gvec_c=self.Gvec_Gc[iG], q_qc=self.ibzq_qc.copy()) self.vint_Gq.append(v_q) if self.print_coulomb: self.printtxt('') self.printtxt( 'Average kernel relative to bare kernel - \int v(q)dq / v(q0): ' ) self.printtxt(' G: % s' % self.Gvec_Gc[iG]) for iq in range(len(v_q)): q_s = ' q = [%1.2f, %1.2f, %1.2f]: ' % ( self.ibzq_qc[iq, 0], self.ibzq_qc[iq, 1], self.ibzq_qc[iq, 2]) v_rel = v_q[iq] / v0_q[iq] self.printtxt(q_s + '%1.3f' % v_rel) self.printtxt('') self.V_qGG = self.full_bare_interaction()
def get_phi_qaGp(self): N1_max = 0 N2_max = 0 natoms = len(self.calc.wfs.setups) for id in range(natoms): N1 = self.npw N2 = self.calc.wfs.setups[id].ni**2 if N1 > N1_max: N1_max = N1 if N2 > N2_max: N2_max = N2 nbzq = self.kd.nbzkpts nbzq, nq_local, q_start, q_end = parallel_partition(nbzq, world.rank, world.size, reshape=False) phimax_qaGp = np.zeros((nq_local, natoms, N1_max, N2_max), dtype=complex) #phimax_qaGp = np.zeros((nbzq, natoms, N1_max, N2_max), dtype=complex) t0 = time() for iq in range(nq_local): q_c = self.bzq_qc[iq + q_start] tmp_aGp = self.get_phi_aGp(q_c, parallel=False) for id in range(natoms): N1, N2 = tmp_aGp[id].shape phimax_qaGp[iq, id, :N1, :N2] = tmp_aGp[id] self.timing(iq * world.size, t0, nq_local, 'iq') world.barrier() # Write to disk filename = 'phi_qaGp' if world.rank == 0: w = Writer(filename) w.dimension('nbzq', nbzq) w.dimension('natoms', natoms) w.dimension('nG', N1_max) w.dimension('nii', N2_max) w.add('phi_qaGp', ( 'nbzq', 'natoms', 'nG', 'nii', ), dtype=complex) for q in range(nbzq): residual = nbzq % size N_local = nbzq // size if q < residual * (N_local + 1): qrank = q // (N_local + 1) else: qrank = (q - residual * (N_local + 1)) // N_local + residual if qrank == 0: if world.rank == 0: phi_aGp = phimax_qaGp[q - q_start] else: if world.rank == qrank: phi_aGp = phimax_qaGp[q - q_start] world.send(phi_aGp, 0, q) elif world.rank == 0: world.receive(phi_aGp, qrank, q) if world.rank == 0: w.fill(phi_aGp) if world.rank == 0: w.close() world.barrier()