def __init__(self, cell, kpts=numpy.zeros((1, 3))): self.cell = cell self.stdout = cell.stdout self.verbose = cell.verbose self.max_memory = cell.max_memory self.kpts = kpts # default is gamma point self.kpts_band = None self.auxbasis = None if cell.dimension == 0: self.eta = 0.2 self.gs = cell.gs else: ke_cutoff = tools.gs_to_cutoff(cell.lattice_vectors(), cell.gs) ke_cutoff = ke_cutoff[:cell.dimension].min() self.eta = min( aft.estimate_eta_for_ke_cutoff(cell, ke_cutoff, cell.precision), estimate_eta(cell, cell.precision)) ke_cutoff = aft.estimate_ke_cutoff_for_eta(cell, self.eta, cell.precision) self.gs = tools.cutoff_to_gs(cell.lattice_vectors(), ke_cutoff) self.gs[cell.dimension:] = cell.gs[cell.dimension:] # Not input options self.exxdiv = None # to mimic KRHF/KUHF object in function get_coulG self.auxcell = None self.blockdim = 240 self.linear_dep_threshold = LINEAR_DEP_THR self._j_only = False # If _cderi_to_save is specified, the 3C-integral tensor will be saved in this file. self._cderi_to_save = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR) # If _cderi is specified, the 3C-integral tensor will be read from this file self._cderi = None self._keys = set(self.__dict__.keys())
def __init__(self, cell, kpts=numpy.zeros((1, 3))): self.cell = cell self.stdout = cell.stdout self.verbose = cell.verbose self.max_memory = cell.max_memory self.kpts = kpts # default is gamma point self.kpts_band = None self._auxbasis = None # Search for optimized eta and mesh here. if cell.dimension == 0: self.eta = 0.2 self.mesh = cell.mesh else: ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), cell.mesh) ke_cutoff = ke_cutoff[:cell.dimension].min() eta_cell = aft.estimate_eta_for_ke_cutoff(cell, ke_cutoff, cell.precision) eta_guess = estimate_eta(cell, cell.precision) if eta_cell < eta_guess: self.eta = eta_cell # TODO? Round off mesh to the nearest odd numbers. # Odd number of grids is preferred because even number of # grids may break the conjugation symmetry between the # k-points k and -k. #?self.mesh = [(n//2)*2+1 for n in cell.mesh] self.mesh = cell.mesh else: self.eta = eta_guess ke_cutoff = aft.estimate_ke_cutoff_for_eta( cell, self.eta, cell.precision) self.mesh = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_cutoff) if cell.dimension < 2 or cell.low_dim_ft_type == 'inf_vacuum': self.mesh[cell.dimension:] = cell.mesh[cell.dimension:] # exp_to_discard to remove diffused fitting functions. The diffused # fitting functions may cause linear dependency in DF metric. Removing # the fitting functions whose exponents are smaller than exp_to_discard # can improve the linear dependency issue. However, this parameter # affects the quality of the auxiliary basis. The default value of # this parameter was set to 0.2 in v1.5.1 or older and was changed to # 0 since v1.5.2. self.exp_to_discard = cell.exp_to_discard # The following attributes are not input options. self.exxdiv = None # to mimic KRHF/KUHF object in function get_coulG self.auxcell = None self.blockdim = getattr(__config__, 'pbc_df_df_DF_blockdim', 240) self.linear_dep_threshold = LINEAR_DEP_THR self._j_only = False # If _cderi_to_save is specified, the 3C-integral tensor will be saved in this file. self._cderi_to_save = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR) # If _cderi is specified, the 3C-integral tensor will be read from this file self._cderi = None self._keys = set(self.__dict__.keys())
def eta(self): if self._eta is not None: return self._eta else: cell = self.cell if cell.dimension == 0: return 0.2 ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), self.mesh) ke_cutoff = ke_cutoff[:cell.dimension].min() return aft.estimate_eta_for_ke_cutoff(cell, ke_cutoff, cell.precision)
def __init__(self, cell, kpts=numpy.zeros((1,3))): self.cell = cell self.stdout = cell.stdout self.verbose = cell.verbose self.max_memory = cell.max_memory self.kpts = kpts # default is gamma point self.kpts_band = None self._auxbasis = None # Search for optimized eta and mesh here. if cell.dimension == 0: self.eta = 0.2 self.mesh = cell.mesh else: ke_cutoff = tools.mesh_to_cutoff(cell.lattice_vectors(), cell.mesh) ke_cutoff = ke_cutoff[:cell.dimension].min() eta_cell = aft.estimate_eta_for_ke_cutoff(cell, ke_cutoff, cell.precision) eta_guess = estimate_eta(cell, cell.precision) if eta_cell < eta_guess: self.eta = eta_cell # TODO? Round off mesh to the nearest odd numbers. # Odd number of grids is preferred because even number of # grids may break the conjugation symmetry between the # k-points k and -k. #?self.mesh = [(n//2)*2+1 for n in cell.mesh] self.mesh = cell.mesh else: self.eta = eta_guess ke_cutoff = aft.estimate_ke_cutoff_for_eta(cell, self.eta, cell.precision) self.mesh = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_cutoff) if cell.dimension < 2 or cell.low_dim_ft_type == 'inf_vacuum': self.mesh[cell.dimension:] = cell.mesh[cell.dimension:] # exp_to_discard to remove diffused fitting functions. The diffused # fitting functions may cause linear dependency in DF metric. Removing # the fitting functions whose exponents are smaller than exp_to_discard # can improve the linear dependency issue. However, this parameter # affects the quality of the auxiliary basis. The default value of # this parameter was set to 0.2 in v1.5.1 or older and was changed to # 0 since v1.5.2. self.exp_to_discard = cell.exp_to_discard # The following attributes are not input options. self.exxdiv = None # to mimic KRHF/KUHF object in function get_coulG self.auxcell = None self.blockdim = getattr(__config__, 'pbc_df_df_DF_blockdim', 240) self.linear_dep_threshold = LINEAR_DEP_THR self._j_only = False # If _cderi_to_save is specified, the 3C-integral tensor will be saved in this file. self._cderi_to_save = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR) # If _cderi is specified, the 3C-integral tensor will be read from this file self._cderi = None self._keys = set(self.__dict__.keys())
def build(self, omega=None, direct_scf_tol=None): cpu0 = (time.clock(), time.time()) cell = self.cell kpts = self.kpts k_scaled = cell.get_scaled_kpts(kpts).sum(axis=0) k_mod_to_half = k_scaled * 2 - (k_scaled * 2).round(0) if abs(k_mod_to_half).sum() > 1e-5: raise NotImplementedError('k-points must be symmetryic') if omega is not None: self.omega = omega if self.omega is None: # Search a proper range-separation parameter omega that can balance the # computational cost between the real space integrals and moment space # integrals self.omega, self.mesh, self.ke_cutoff = _guess_omega( cell, kpts, self.mesh) else: self.ke_cutoff = aft.estimate_ke_cutoff_for_omega(cell, self.omega) self.mesh = pbctools.cutoff_to_mesh(cell.lattice_vectors(), self.ke_cutoff) logger.info(self, 'omega = %.15g ke_cutoff = %s mesh = %s', self.omega, self.ke_cutoff, self.mesh) if direct_scf_tol is None: direct_scf_tol = cell.precision**1.5 logger.debug(self, 'Set direct_scf_tol %g', direct_scf_tol) self.cell_rs = cell_rs = _re_contract_cell(cell, self.ke_cutoff) self.bvk_kmesh = kmesh = k2gamma.kpts_to_kmesh(cell_rs, kpts) bvkcell, phase = k2gamma.get_phase(cell_rs, kpts, kmesh) self.bvkmesh_Ls = Ks = k2gamma.translation_vectors_for_kmesh( cell_rs, kmesh) self.bvkcell = bvkcell self.phase = phase # Given ke_cutoff, eta corresponds to the most steep Gaussian basis # of which the Coulomb integrals can be accurately computed in moment # space. eta = aft.estimate_eta_for_ke_cutoff(cell, self.ke_cutoff, precision=cell.precision) # * Assuming the most steep function in smooth basis has exponent eta, # with attenuation parameter omega, rcut_sr is the distance of which # the value of attenuated Coulomb integrals of four shells |eta> is # smaller than the required precision. # * The attenuated coulomb integrals between four s-type Gaussians # (2*a/pi)^{3/4}exp(-a*r^2) is # (erfc(omega*a^0.5/(omega^2+a)^0.5*R) - erfc(a^0.5*R)) / R # if two Gaussians on one center and the other two on another center # and the distance between the two centers are R. # * The attenuated coulomb integrals between two spherical charge # distributions is # ~(pi/eta)^3/2 (erfc(tau*(eta/2)^0.5*R) - erfc((eta/2)^0.5*R)) / R # tau = omega/sqrt(omega^2 + eta/2) # if the spherical charge distribution is the product of above s-type # Gaussian with exponent eta and a very smooth function. # When R is large, the attenuated Coulomb integral is # ~= (pi/eta)^3/2 erfc(tau*(eta/2)^0.5*R) / R # ~= pi/(tau*eta^2*R^2) exp(-tau^2*eta*R^2/2) tau = self.omega / (self.omega**2 + eta / 2)**.5 rcut_sr = 10 # initial guess rcut_sr = (-np.log(direct_scf_tol * tau * (eta * rcut_sr)**2 / np.pi) / (tau**2 * eta / 2))**.5 logger.debug(self, 'eta = %g rcut_sr = %g', eta, rcut_sr) # Ls is the translation vectors to mimic periodicity of a cell Ls = bvkcell.get_lattice_Ls(rcut=cell.rcut + rcut_sr) self.supmol_Ls = Ls = Ls[np.linalg.norm(Ls, axis=1).argsort()] supmol = _make_extended_mole(cell_rs, Ls, Ks, self.omega, direct_scf_tol) self.supmol = supmol nkpts = len(self.bvkmesh_Ls) nbas = cell_rs.nbas n_steep, n_local, n_diffused = cell_rs._nbas_each_set n_compact = n_steep + n_local bas_mask = supmol._bas_mask self.bvk_bas_mask = bvk_bas_mask = bas_mask.any(axis=2) # Some basis in bvk-cell are not presented in the supmol. They can be # skipped when computing SR integrals self.bvkcell._bas = bvkcell._bas[bvk_bas_mask.ravel()] # Record the mapping between the dense bvkcell basis and the # original sparse bvkcell basis bvk_cell_idx = np.repeat(np.arange(nkpts)[:, None], nbas, axis=1) self.bvk_cell_id = bvk_cell_idx[bvk_bas_mask].astype(np.int32) cell0_shl_idx = np.repeat(np.arange(nbas)[None, :], nkpts, axis=0) self.cell0_shl_id = cell0_shl_idx[bvk_bas_mask].astype(np.int32) logger.timer_debug1(self, 'initializing supmol', *cpu0) logger.info(self, 'sup-mol nbas = %d cGTO = %d pGTO = %d', supmol.nbas, supmol.nao, supmol.npgto_nr()) supmol.omega = -self.omega # Set short range coulomb with supmol.with_integral_screen(direct_scf_tol**2): vhfopt = _vhf.VHFOpt(supmol, 'int2e_sph', qcondname=libpbc.PBCVHFsetnr_direct_scf) vhfopt.direct_scf_tol = direct_scf_tol self.vhfopt = vhfopt logger.timer(self, 'initializing vhfopt', *cpu0) q_cond = vhfopt.get_q_cond((supmol.nbas, supmol.nbas)) idx = supmol._images_loc bvk_q_cond = lib.condense('NP_absmax', q_cond, idx, idx) ovlp_mask = bvk_q_cond > direct_scf_tol # Remove diffused-diffused block if n_diffused > 0: diffused_mask = np.zeros_like(bvk_bas_mask) diffused_mask[:, n_compact:] = True diffused_mask = diffused_mask[bvk_bas_mask] ovlp_mask[diffused_mask[:, None] & diffused_mask] = False self.ovlp_mask = ovlp_mask.astype(np.int8) # mute rcut_threshold, divide basis into two sets only cell_lr_aft = _re_contract_cell(cell, self.ke_cutoff, -1, verbose=0) self.lr_aft = lr_aft = _LongRangeAFT(cell_lr_aft, kpts, self.omega, self.bvk_kmesh) lr_aft.ke_cutoff = self.ke_cutoff lr_aft.mesh = self.mesh lr_aft.eta = eta return self