def check_sanity(self): lib.StreamObject.check_sanity(self) cell = self.cell if cell.dimension < 3: raise RuntimeError( 'FFTDF method does not support low-dimension ' 'PBC system. DF, MDF or AFTDF methods should ' 'be used.\nSee also examples/pbc/31-low_dimensional_pbc.py') if not cell.has_ecp(): logger.warn( self, 'FFTDF integrals are found in all-electron ' 'calculation. It often causes huge error.\n' 'Recommended methods are DF or MDF. In SCF calculation, ' 'they can be initialized as\n' ' mf = mf.density_fit()\nor\n' ' mf = mf.mix_density_fit()') if cell.ke_cutoff is None: ke_cutoff = tools.gs_to_cutoff(cell.lattice_vectors(), self.gs).min() else: ke_cutoff = numpy.min(cell.ke_cutoff) ke_guess = estimate_ke_cutoff(cell, cell.precision) if ke_cutoff < ke_guess * .8: gs_guess = tools.cutoff_to_gs(cell.lattice_vectors(), ke_guess) logger.warn( self, 'ke_cutoff/gs (%g / %s) is not enough for FFTDF ' 'to get integral accuracy %g.\nCoulomb integral error ' 'is ~ %.2g Eh.\nRecomended ke_cutoff/gs are %g / %s.', ke_cutoff, self.gs, cell.precision, error_for_ke_cutoff(cell, ke_cutoff), ke_guess, gs_guess) return self
def check_sanity(self): lib.StreamObject.check_sanity(self) cell = self.cell if not cell.has_ecp(): logger.warn( self, 'AFTDF integrals are found in all-electron ' 'calculation. It often causes huge error.\n' 'Recommended methods are DF or MDF. In SCF calculation, ' 'they can be initialized as\n' ' mf = mf.density_fit()\nor\n' ' mf = mf.mix_density_fit()') if cell.dimension > 0: if cell.ke_cutoff is None: ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), self.mesh) ke_cutoff = ke_cutoff[:cell.dimension].min() else: ke_cutoff = numpy.min(cell.ke_cutoff) ke_guess = estimate_ke_cutoff(cell, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if ke_cutoff < ke_guess * KE_SCALING: logger.warn( self, 'ke_cutoff/mesh (%g / %s) is not enough for AFTDF ' 'to get integral accuracy %g.\nCoulomb integral error ' 'is ~ %.2g Eh.\nRecommended ke_cutoff/mesh are %g / %s.', ke_cutoff, self.mesh, cell.precision, error_for_ke_cutoff(cell, ke_cutoff), ke_guess, mesh_guess) else: mesh_guess = numpy.copy(self.mesh) if cell.dimension < 3: err = numpy.exp(-0.436392335 * min(self.mesh[cell.dimension:]) - 2.99944305) err *= cell.nelectron meshz = pbcgto.cell._mesh_inf_vaccum(cell) mesh_guess[cell.dimension:] = int(meshz) if err > cell.precision * 10: logger.warn( self, 'mesh %s of AFTDF may not be enough to get ' 'integral accuracy %g for %dD PBC system.\n' 'Coulomb integral error is ~ %.2g Eh.\n' 'Recommended mesh is %s.', self.mesh, cell.precision, cell.dimension, err, mesh_guess) if (cell.mesh[cell.dimension:] / (1. * meshz) > 1.1).any(): meshz = pbcgto.cell._mesh_inf_vaccum(cell) logger.warn( self, 'setting mesh %s of AFTDF too high in non-periodic direction ' '(=%s) can result in an unnecessarily slow calculation.\n' 'For coulomb integral error of ~ %.2g Eh in %dD PBC, \n' 'a recommended mesh for non-periodic direction is %s.', self.mesh, self.mesh[cell.dimension:], cell.precision, cell.dimension, mesh_guess[cell.dimension:]) return self
def check_sanity(self): lib.StreamObject.check_sanity(self) cell = self.cell if not cell.has_ecp(): logger.warn(self, 'AFTDF integrals are found in all-electron ' 'calculation. It often causes huge error.\n' 'Recommended methods are DF or MDF. In SCF calculation, ' 'they can be initialized as\n' ' mf = mf.density_fit()\nor\n' ' mf = mf.mix_density_fit()') if cell.dimension > 0: if cell.ke_cutoff is None: ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), self.mesh) ke_cutoff = ke_cutoff[:cell.dimension].min() else: ke_cutoff = numpy.min(cell.ke_cutoff) ke_guess = estimate_ke_cutoff(cell, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if ke_cutoff < ke_guess * KE_SCALING: logger.warn(self, 'ke_cutoff/mesh (%g / %s) is not enough for AFTDF ' 'to get integral accuracy %g.\nCoulomb integral error ' 'is ~ %.2g Eh.\nRecommended ke_cutoff/mesh are %g / %s.', ke_cutoff, self.mesh, cell.precision, error_for_ke_cutoff(cell, ke_cutoff), ke_guess, mesh_guess) else: mesh_guess = numpy.copy(self.mesh) if cell.dimension < 3: err = numpy.exp(-0.436392335*min(self.mesh[cell.dimension:]) - 2.99944305) err *= cell.nelectron meshz = pbcgto.cell._mesh_inf_vaccum(cell) mesh_guess[cell.dimension:] = int(meshz) if err > cell.precision*10: logger.warn(self, 'mesh %s of AFTDF may not be enough to get ' 'integral accuracy %g for %dD PBC system.\n' 'Coulomb integral error is ~ %.2g Eh.\n' 'Recommended mesh is %s.', self.mesh, cell.precision, cell.dimension, err, mesh_guess) if (cell.mesh[cell.dimension:]/(1.*meshz) > 1.1).any(): meshz = pbcgto.cell._mesh_inf_vaccum(cell) logger.warn(self, 'setting mesh %s of AFTDF too high in non-periodic direction ' '(=%s) can result in an unnecessarily slow calculation.\n' 'For coulomb integral error of ~ %.2g Eh in %dD PBC, \n' 'a recommended mesh for non-periodic direction is %s.', self.mesh, self.mesh[cell.dimension:], cell.precision, cell.dimension, mesh_guess[cell.dimension:]) return self
def check_sanity(self): lib.StreamObject.check_sanity(self) cell = self.cell if not cell.has_ecp(): logger.warn( self, 'FFTDF integrals are found in all-electron ' 'calculation. It often causes huge error.\n' 'Recommended methods are DF or MDF. In SCF calculation, ' 'they can be initialized as\n' ' mf = mf.density_fit()\nor\n' ' mf = mf.mix_density_fit()') if cell.dimension > 0: if cell.ke_cutoff is None: ke_cutoff = tools.gs_to_cutoff(cell.lattice_vectors(), self.gs) ke_cutoff = ke_cutoff[:cell.dimension].min() else: ke_cutoff = numpy.min(cell.ke_cutoff) ke_guess = estimate_ke_cutoff(cell, cell.precision) if ke_cutoff < ke_guess * .8: gs_guess = tools.cutoff_to_gs(cell.lattice_vectors(), ke_guess) logger.warn( self, 'ke_cutoff/gs (%g / %s) is not enough for FFTDF ' 'to get integral accuracy %g.\nCoulomb integral error ' 'is ~ %.2g Eh.\nRecomended ke_cutoff/gs are %g / %s.', ke_cutoff, self.gs, cell.precision, error_for_ke_cutoff(cell, ke_cutoff), ke_guess, gs_guess) else: gs_guess = numpy.copy(self.gs) if cell.dimension < 3: err = numpy.exp(-0.87278467 * min(self.gs[cell.dimension:]) - 2.99944305) err *= cell.nelectron if err > cell.precision * 10: gz = numpy.log( cell.nelectron / cell.precision) / 0.8727847 - 3.4366358 gs_guess[cell.dimension:] = int(gz) logger.warn( self, 'gs %s of AFTDF may not be enough to get ' 'integral accuracy %g for %dD PBC system.\n' 'Coulomb integral error is ~ %.2g Eh.\n' 'Recomended gs is %s.', self.gs, cell.precision, cell.dimension, err, gs_guess) return self
def check_sanity(self): lib.StreamObject.check_sanity(self) cell = self.cell if cell.dimension < 2: raise RuntimeError( 'FFTDF method does not support 0D/1D low-dimension ' 'PBC system. DF, MDF or AFTDF methods should ' 'be used.\nSee also examples/pbc/31-low_dimensional_pbc.py') if cell.dimension == 2 and self.low_dim_ft_type is None: raise RuntimeError( 'FFTDF method does not support low_dim_ft_type of None ' 'for 2D systems. Supported types include \'analytic_2d_1\'. ' '\nSee also examples/pbc/32-graphene.py') if not cell.has_ecp(): logger.warn( self, 'FFTDF integrals are found in all-electron ' 'calculation. It often causes huge error.\n' 'Recommended methods are DF or MDF. In SCF calculation, ' 'they can be initialized as\n' ' mf = mf.density_fit()\nor\n' ' mf = mf.mix_density_fit()') if cell.ke_cutoff is None: ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), self.mesh).min() else: ke_cutoff = numpy.min(cell.ke_cutoff) ke_guess = estimate_ke_cutoff(cell, cell.precision) if ke_cutoff < ke_guess * KE_SCALING: mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) logger.warn( self, 'ke_cutoff/mesh (%g / %s) is not enough for FFTDF ' 'to get integral accuracy %g.\nCoulomb integral error ' 'is ~ %.2g Eh.\nRecommended ke_cutoff/mesh are %g / %s.', ke_cutoff, self.mesh, cell.precision, error_for_ke_cutoff(cell, ke_cutoff), ke_guess, mesh_guess) return self
def _dip_correction(mf): '''Makov-Payne corrections for charged systems.''' from pyscf.pbc import tools from pyscf.pbc.dft import gen_grid log = logger.new_logger(mf) cell = mf.cell a = cell.lattice_vectors() b = np.linalg.inv(a).T grids = gen_grid.UniformGrids(cell) ke_cutoff = gto.estimate_ke_cutoff(cell, 1e-5) grids.mesh = tools.cutoff_to_mesh(a, ke_cutoff) dm = mf.make_rdm1() rho = mf.get_rho(dm, grids, mf.kpt) origin = _search_dipole_gauge_origin(cell, grids, rho, log) def shift_grids(r): r_frac = lib.dot(r - origin, b.T) # Grids on the boundary (r_frac == +/-0.5) of the new cell may lead to # unbalanced contributions to the dipole moment. Exclude them from the # dipole and quadrupole r_frac[r_frac == 0.5] = 0 r_frac[r_frac == -0.5] = 0 r_frac[r_frac > 0.5] -= 1 r_frac[r_frac < -0.5] += 1 r = lib.dot(r_frac, a) return r # SC BCC FCC madelung = (-2.83729747948, -3.63923344951, -4.58486207411) vol = cell.vol L = vol**(1. / 3) chg = cell.charge # epsilon is the dielectric constant of the system. For systems # surrounded by vacuum, epsilon = 1. epsilon = 1 # Energy correction of point charges of a simple cubic lattice. de_mono = -chg**2 * np.array(madelung) / (2 * L * epsilon) # dipole energy correction r_e = shift_grids(grids.coords) r_nuc = shift_grids(cell.atom_coords()) charges = cell.atom_charges() e_dip = np.einsum('g,g,gx->x', rho, grids.weights, r_e) nuc_dip = np.einsum('g,gx->x', charges, r_nuc) dip = nuc_dip - e_dip de_dip = -2. * np.pi / (3 * cell.vol) * np.linalg.norm(dip)**2 # quadrupole energy correction if abs(a - np.eye(3) * L).max() > 1e-5: logger.warn( mf, 'System is not cubic cell. Quadrupole energy ' 'correction is inaccurate since it is developed based on ' 'cubic cell.') e_quad = np.einsum('g,g,gx,gx->', rho, grids.weights, r_e, r_e) nuc_quad = np.einsum('g,gx,gx->', charges, r_nuc, r_nuc) quad = nuc_quad - e_quad de_quad = 2. * np.pi / (3 * cell.vol) * quad de = de_mono + de_dip + de_quad return de_mono, de_dip, de_quad, de
def get_pp_loc_part1(mydf, kpts=None): cell = mydf.cell if kpts is None: kpts_lst = numpy.zeros((1, 3)) else: kpts_lst = numpy.reshape(kpts, (-1, 3)) log = logger.Logger(mydf.stdout, mydf.verbose) t0 = t1 = (time.clock(), time.time()) mesh = numpy.asarray(mydf.mesh) nkpts = len(kpts_lst) nao = cell.nao_nr() nao_pair = nao * (nao + 1) // 2 charges = cell.atom_charges() kpt_allow = numpy.zeros(3) if mydf.eta == 0: if cell.dimension > 0: ke_guess = estimate_ke_cutoff(cell, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any( mesh[:cell.dimension] < mesh_guess[:cell.dimension] * .8): logger.warn( mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) Gv, Gvbase, kws = cell.get_Gv_weights(mesh) vpplocG = pseudo.pp_int.get_gth_vlocG_part1(cell, Gv) vpplocG = -numpy.einsum('ij,ij->j', cell.get_SI(Gv), vpplocG) vpplocG *= kws vG = vpplocG vj = numpy.zeros((nkpts, nao_pair), dtype=numpy.complex128) else: if cell.dimension > 0: ke_guess = estimate_ke_cutoff_for_eta(cell, mydf.eta, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any(mesh < mesh_guess * .8): logger.warn( mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) mesh_min = numpy.min((mesh_guess, mesh), axis=0) if cell.dimension < 2 or cell.low_dim_ft_type == 'inf_vacuum': mesh[:cell.dimension] = mesh_min[:cell.dimension] else: mesh = mesh_min Gv, Gvbase, kws = cell.get_Gv_weights(mesh) nuccell = _compensate_nuccell(mydf) # PP-loc part1 is handled by fakenuc in _int_nuc_vloc vj = lib.asarray(mydf._int_nuc_vloc(nuccell, kpts_lst)) t0 = t1 = log.timer_debug1('vnuc pass1: analytic int', *t0) coulG = tools.get_coulG(cell, kpt_allow, mesh=mesh, Gv=Gv) * kws aoaux = ft_ao.ft_ao(nuccell, Gv) vG = numpy.einsum('i,xi->x', -charges, aoaux) * coulG max_memory = max(2000, mydf.max_memory - lib.current_memory()[0]) for aoaoks, p0, p1 in mydf.ft_loop(mesh, kpt_allow, kpts_lst, max_memory=max_memory, aosym='s2'): for k, aoao in enumerate(aoaoks): # rho_ij(G) nuc(-G) / G^2 # = [Re(rho_ij(G)) + Im(rho_ij(G))*1j] [Re(nuc(G)) - Im(nuc(G))*1j] / G^2 if gamma_point(kpts_lst[k]): vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].real, aoao.real) vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].imag, aoao.imag) else: vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].conj(), aoao) t1 = log.timer_debug1('contracting Vnuc [%s:%s]' % (p0, p1), *t1) log.timer_debug1('contracting Vnuc', *t0) vj_kpts = [] for k, kpt in enumerate(kpts_lst): if gamma_point(kpt): vj_kpts.append(lib.unpack_tril(vj[k].real.copy())) else: vj_kpts.append(lib.unpack_tril(vj[k])) if kpts is None or numpy.shape(kpts) == (3, ): vj_kpts = vj_kpts[0] return numpy.asarray(vj_kpts)
def _dip_correction(mf): '''Makov-Payne corrections for charged systems.''' from pyscf.pbc import gto from pyscf.pbc import tools from pyscf.pbc.dft import gen_grid log = logger.new_logger(mf) cell = mf.cell a = cell.lattice_vectors() b = np.linalg.inv(a).T grids = gen_grid.UniformGrids(cell) ke_cutoff = gto.estimate_ke_cutoff(cell, 1e-5) grids.mesh = tools.cutoff_to_mesh(a, ke_cutoff) dm = mf.make_rdm1() rho = mf.get_rho(dm, grids, mf.kpt) origin = _search_dipole_gauge_origin(cell, grids, rho, log) def shift_grids(r): r_frac = lib.dot(r - origin, b.T) # Grids on the boundary (r_frac == +/-0.5) of the new cell may lead to # unbalanced contributions to the dipole moment. Exclude them from the # dipole and quadrupole r_frac[r_frac== 0.5] = 0 r_frac[r_frac==-0.5] = 0 r_frac[r_frac > 0.5] -= 1 r_frac[r_frac <-0.5] += 1 r = lib.dot(r_frac, a) return r # SC BCC FCC madelung = (-2.83729747948, -3.63923344951, -4.58486207411) vol = cell.vol L = vol ** (1./3) chg = cell.charge # epsilon is the dielectric constant of the system. For systems # surrounded by vacuum, epsilon = 1. epsilon = 1 # Energy correction of point charges of a simple cubic lattice. de_mono = - chg**2 * np.array(madelung) / (2 * L * epsilon) # dipole energy correction r_e = shift_grids(grids.coords) r_nuc = shift_grids(cell.atom_coords()) charges = cell.atom_charges() e_dip = np.einsum('g,g,gx->x', rho, grids.weights, r_e) nuc_dip = np.einsum('g,gx->x', charges, r_nuc) dip = nuc_dip - e_dip de_dip = -2.*np.pi/(3*cell.vol) * np.linalg.norm(dip)**2 # quadrupole energy correction if abs(a - np.eye(3)*L).max() > 1e-5: logger.warn(mf, 'System is not cubic cell. Quadrupole energy ' 'correction is inaccurate since it is developed based on ' 'cubic cell.') e_quad = np.einsum('g,g,gx,gx->', rho, grids.weights, r_e, r_e) nuc_quad = np.einsum('g,gx,gx->', charges, r_nuc, r_nuc) quad = nuc_quad - e_quad de_quad = 2.*np.pi/(3*cell.vol) * quad de = de_mono + de_dip + de_quad return de_mono, de_dip, de_quad, de
def get_nuc(mydf, kpts=None): cell = mydf.cell if kpts is None: kpts_lst = numpy.zeros((1, 3)) else: kpts_lst = numpy.reshape(kpts, (-1, 3)) log = logger.Logger(mydf.stdout, mydf.verbose) t0 = t1 = (time.clock(), time.time()) mesh = numpy.asarray(mydf.mesh) nkpts = len(kpts_lst) nao = cell.nao_nr() nao_pair = nao * (nao + 1) // 2 charges = cell.atom_charges() kpt_allow = numpy.zeros(3) if mydf.eta == 0: if cell.dimension > 0: ke_guess = estimate_ke_cutoff(cell, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any(mesh < mesh_guess * .8): logger.warn( mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) Gv, Gvbase, kws = cell.get_Gv_weights(mesh) vpplocG = pseudo.pp_int.get_gth_vlocG_part1(cell, Gv) vpplocG = -numpy.einsum('ij,ij->j', cell.get_SI(Gv), vpplocG) v1 = -vpplocG.copy() if cell.dimension == 1 or cell.dimension == 2: G0idx, SI_on_z = pbcgto.cell._SI_for_uniform_model_charge(cell, Gv) coulG = 4 * numpy.pi / numpy.linalg.norm(Gv[G0idx], axis=1)**2 vpplocG[G0idx] += charges.sum() * SI_on_z * coulG vpplocG *= kws vG = vpplocG vj = numpy.zeros((nkpts, nao_pair), dtype=numpy.complex128) else: if cell.dimension > 0: ke_guess = estimate_ke_cutoff_for_eta(cell, mydf.eta, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any(mesh < mesh_guess * .8): logger.warn( mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) mesh_min = numpy.min( (mesh_guess[:cell.dimension], mesh[:cell.dimension]), axis=0) mesh[:cell.dimension] = mesh_min.astype(int) Gv, Gvbase, kws = cell.get_Gv_weights(mesh) nuccell = copy.copy(cell) half_sph_norm = .5 / numpy.sqrt(numpy.pi) norm = half_sph_norm / gto.gaussian_int(2, mydf.eta) chg_env = [mydf.eta, norm] ptr_eta = cell._env.size ptr_norm = ptr_eta + 1 chg_bas = [[ia, 0, 1, 1, 0, ptr_eta, ptr_norm, 0] for ia in range(cell.natm)] nuccell._atm = cell._atm nuccell._bas = numpy.asarray(chg_bas, dtype=numpy.int32) nuccell._env = numpy.hstack((cell._env, chg_env)) # PP-loc part1 is handled by fakenuc in _int_nuc_vloc vj = lib.asarray(mydf._int_nuc_vloc(nuccell, kpts_lst)) t0 = t1 = log.timer_debug1('vnuc pass1: analytic int', *t0) coulG = tools.get_coulG(cell, kpt_allow, mesh=mesh, Gv=Gv) * kws aoaux = ft_ao.ft_ao(nuccell, Gv) vG = numpy.einsum('i,xi->x', -charges, aoaux) * coulG if cell.dimension == 1 or cell.dimension == 2: G0idx, SI_on_z = pbcgto.cell._SI_for_uniform_model_charge(cell, Gv) vG[G0idx] += charges.sum() * SI_on_z * coulG[G0idx] max_memory = max(2000, mydf.max_memory - lib.current_memory()[0]) for aoaoks, p0, p1 in mydf.ft_loop(mesh, kpt_allow, kpts_lst, max_memory=max_memory, aosym='s2'): for k, aoao in enumerate(aoaoks): # rho_ij(G) nuc(-G) / G^2 # = [Re(rho_ij(G)) + Im(rho_ij(G))*1j] [Re(nuc(G)) - Im(nuc(G))*1j] / G^2 if gamma_point(kpts_lst[k]): vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].real, aoao.real) vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].imag, aoao.imag) else: vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].conj(), aoao) t1 = log.timer_debug1('contracting Vnuc [%s:%s]' % (p0, p1), *t1) log.timer_debug1('contracting Vnuc', *t0) vj_kpts = [] for k, kpt in enumerate(kpts_lst): if gamma_point(kpt): vj_kpts.append(lib.unpack_tril(vj[k].real.copy())) else: vj_kpts.append(lib.unpack_tril(vj[k])) if kpts is None or numpy.shape(kpts) == (3, ): vj_kpts = vj_kpts[0] return numpy.asarray(vj_kpts)
def get_pp_loc_part1(mydf, kpts=None): cell = mydf.cell if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) log = logger.Logger(mydf.stdout, mydf.verbose) t0 = t1 = (time.clock(), time.time()) mesh = numpy.asarray(mydf.mesh) nkpts = len(kpts_lst) nao = cell.nao_nr() nao_pair = nao * (nao+1) // 2 charges = cell.atom_charges() kpt_allow = numpy.zeros(3) if mydf.eta == 0: if cell.dimension > 0: ke_guess = estimate_ke_cutoff(cell, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any(mesh[:cell.dimension] < mesh_guess[:cell.dimension]*.8): logger.warn(mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) Gv, Gvbase, kws = cell.get_Gv_weights(mesh) vpplocG = pseudo.pp_int.get_gth_vlocG_part1(cell, Gv) vpplocG = -numpy.einsum('ij,ij->j', cell.get_SI(Gv), vpplocG) vpplocG *= kws vG = vpplocG vj = numpy.zeros((nkpts,nao_pair), dtype=numpy.complex128) else: if cell.dimension > 0: ke_guess = estimate_ke_cutoff_for_eta(cell, mydf.eta, cell.precision) mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess) if numpy.any(mesh < mesh_guess*.8): logger.warn(mydf, 'mesh %s is not enough for AFTDF.get_nuc function ' 'to get integral accuracy %g.\nRecommended mesh is %s.', mesh, cell.precision, mesh_guess) mesh_min = numpy.min((mesh_guess, mesh), axis=0) if cell.dimension < 2 or cell.low_dim_ft_type == 'inf_vacuum': mesh[:cell.dimension] = mesh_min[:cell.dimension] else: mesh = mesh_min Gv, Gvbase, kws = cell.get_Gv_weights(mesh) nuccell = _compensate_nuccell(mydf) # PP-loc part1 is handled by fakenuc in _int_nuc_vloc vj = lib.asarray(mydf._int_nuc_vloc(nuccell, kpts_lst)) t0 = t1 = log.timer_debug1('vnuc pass1: analytic int', *t0) coulG = tools.get_coulG(cell, kpt_allow, mesh=mesh, Gv=Gv) * kws aoaux = ft_ao.ft_ao(nuccell, Gv) vG = numpy.einsum('i,xi->x', -charges, aoaux) * coulG max_memory = max(2000, mydf.max_memory-lib.current_memory()[0]) for aoaoks, p0, p1 in mydf.ft_loop(mesh, kpt_allow, kpts_lst, max_memory=max_memory, aosym='s2'): for k, aoao in enumerate(aoaoks): # rho_ij(G) nuc(-G) / G^2 # = [Re(rho_ij(G)) + Im(rho_ij(G))*1j] [Re(nuc(G)) - Im(nuc(G))*1j] / G^2 if gamma_point(kpts_lst[k]): vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].real, aoao.real) vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].imag, aoao.imag) else: vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].conj(), aoao) t1 = log.timer_debug1('contracting Vnuc [%s:%s]'%(p0, p1), *t1) log.timer_debug1('contracting Vnuc', *t0) vj_kpts = [] for k, kpt in enumerate(kpts_lst): if gamma_point(kpt): vj_kpts.append(lib.unpack_tril(vj[k].real.copy())) else: vj_kpts.append(lib.unpack_tril(vj[k])) if kpts is None or numpy.shape(kpts) == (3,): vj_kpts = vj_kpts[0] return numpy.asarray(vj_kpts)