Beispiel #1
0
    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
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #6
0
    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)
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
    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
Beispiel #10
0
    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
Beispiel #11
0
    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()
Beispiel #12
0
    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()