def fast_newton(mf, mo_coeff=None, mo_occ=None, dm0=None, auxbasis=None, dual_basis=None, **newton_kwargs): '''This is a wrap function which combines several operations. This function first setup the initial guess from density fitting calculation then use for Newton solver and call Newton solver. Newton solver attributes [max_cycle_inner, max_stepsize, ah_start_tol, ah_conv_tol, ah_grad_trust_region, ...] can be passed through **newton_kwargs. ''' import copy from pyscf.lib import logger from pyscf import df from pyscf.soscf import newton_ah if auxbasis is None: auxbasis = df.addons.aug_etb_for_dfbasis(mf.mol, 'ahlrichs', beta=2.5) if dual_basis: mf1 = mf.newton() pmol = mf1.mol = newton_ah.project_mol(mf.mol, dual_basis) mf1 = mf1.density_fit(auxbasis) else: mf1 = mf.newton().density_fit(auxbasis) mf1.with_df._compatible_format = False mf1.direct_scf_tol = 1e-7 if getattr(mf, 'grids', None): from pyscf.dft import gen_grid approx_grids = gen_grid.Grids(mf.mol) approx_grids.verbose = 0 approx_grids.level = max(0, mf.grids.level-3) mf1.grids = approx_grids approx_numint = copy.copy(mf._numint) mf1._numint = approx_numint for key in newton_kwargs: setattr(mf1, key, newton_kwargs[key]) if mo_coeff is None or mo_occ is None: mo_coeff, mo_occ = mf.mo_coeff, mf.mo_occ if dm0 is not None: mo_coeff, mo_occ = mf1.from_dm(dm0) elif mo_coeff is None or mo_occ is None: logger.note(mf, '========================================================') logger.note(mf, 'Generating initial guess with DIIS-SCF for newton solver') logger.note(mf, '========================================================') if dual_basis: mf0 = copy.copy(mf) mf0.mol = pmol mf0 = mf0.density_fit(auxbasis) else: mf0 = mf.density_fit(auxbasis) mf0.direct_scf_tol = 1e-7 mf0.conv_tol = 3. mf0.conv_tol_grad = 1. if mf0.level_shift == 0: mf0.level_shift = .2 if getattr(mf, 'grids', None): mf0.grids = approx_grids mf0._numint = approx_numint # Note: by setting small_rho_cutoff, dft.get_veff function may overwrite # approx_grids and approx_numint. It will further changes the corresponding # mf1 grids and _numint. If inital guess dm0 or mo_coeff/mo_occ were given, # dft.get_veff are not executed so that more grid points may be found in # approx_grids. mf0.small_rho_cutoff = mf.small_rho_cutoff * 10 mf0.kernel() mf1.with_df = mf0.with_df mo_coeff, mo_occ = mf0.mo_coeff, mf0.mo_occ if dual_basis: if mo_occ.ndim == 2: mo_coeff =(project_mo_nr2nr(pmol, mo_coeff[0], mf.mol), project_mo_nr2nr(pmol, mo_coeff[1], mf.mol)) else: mo_coeff = project_mo_nr2nr(pmol, mo_coeff, mf.mol) mo_coeff, mo_occ = mf1.from_dm(mf.make_rdm1(mo_coeff,mo_occ)) mf0 = None logger.note(mf, '============================') logger.note(mf, 'Generating initial guess end') logger.note(mf, '============================') mf1.kernel(mo_coeff, mo_occ) mf.converged = mf1.converged mf.e_tot = mf1.e_tot mf.mo_energy = mf1.mo_energy mf.mo_coeff = mf1.mo_coeff mf.mo_occ = mf1.mo_occ # mf = copy.copy(mf) # def mf_kernel(*args, **kwargs): # logger.warn(mf, "fast_newton is a wrap function to quickly setup and call Newton solver. " # "There's no need to call kernel function again for fast_newton.") # del(mf.kernel) # warn once and remove circular depdence # return mf.e_tot # mf.kernel = mf_kernel return mf
def fast_newton(mf, mo_coeff=None, mo_occ=None, dm0=None, auxbasis=None, dual_basis=None, **newton_kwargs): '''This is a wrap function which combines several operations. This function first setup the initial guess from density fitting calculation then use for Newton solver and call Newton solver. Newton solver attributes [max_cycle_inner, max_stepsize, ah_start_tol, ah_conv_tol, ah_grad_trust_region, ...] can be passed through **newton_kwargs. ''' import copy from pyscf.lib import logger from pyscf import df from pyscf.soscf import newton_ah if auxbasis is None: auxbasis = df.addons.aug_etb_for_dfbasis(mf.mol, 'ahlrichs', beta=2.5) if dual_basis: mf1 = newton(mf) pmol = mf1.mol = newton_ah.project_mol(mf.mol, dual_basis) mf1 = density_fit(mf1, auxbasis) else: mf1 = density_fit(newton(mf), auxbasis) mf1.direct_scf_tol = 1e-7 if getattr(mf, 'grids', None): from pyscf.dft import gen_grid approx_grids = gen_grid.Grids(mf.mol) approx_grids.verbose = 0 approx_grids.level = max(0, mf.grids.level-2) mf1.grids = approx_grids approx_numint = copy.copy(mf._numint) mf1._numint = approx_numint for key in newton_kwargs: setattr(mf1, key, newton_kwargs[key]) if mo_coeff is None or mo_occ is None: mo_coeff, mo_occ = mf.mo_coeff, mf.mo_occ if dm0 is not None: mo_coeff, mo_occ = mf1.from_dm(dm0) elif mo_coeff is None or mo_occ is None: logger.note(mf, '========================================================') logger.note(mf, 'Generating initial guess with DIIS-SCF for newton solver') logger.note(mf, '========================================================') if dual_basis: mf0 = copy.copy(mf) mf0.mol = pmol mf0 = density_fit(mf0, auxbasis) else: mf0 = density_fit(mf, auxbasis) mf0.direct_scf_tol = 1e-7 mf0.conv_tol = 3. mf0.conv_tol_grad = 1. if mf0.level_shift == 0: mf0.level_shift = .2 if getattr(mf, 'grids', None): mf0.grids = approx_grids mf0._numint = approx_numint # Note: by setting small_rho_cutoff, dft.get_veff function may overwrite # approx_grids and approx_numint. It will further changes the corresponding # mf1 grids and _numint. If inital guess dm0 or mo_coeff/mo_occ were given, # dft.get_veff are not executed so that more grid points may be found in # approx_grids. mf0.small_rho_cutoff = mf.small_rho_cutoff * 10 mf0.kernel() mf1.with_df = mf0.with_df mo_coeff, mo_occ = mf0.mo_coeff, mf0.mo_occ if dual_basis: if mo_occ.ndim == 2: mo_coeff =(project_mo_nr2nr(pmol, mo_coeff[0], mf.mol), project_mo_nr2nr(pmol, mo_coeff[1], mf.mol)) else: mo_coeff = project_mo_nr2nr(pmol, mo_coeff, mf.mol) mo_coeff, mo_occ = mf1.from_dm(mf.make_rdm1(mo_coeff,mo_occ)) mf0 = None logger.note(mf, '============================') logger.note(mf, 'Generating initial guess end') logger.note(mf, '============================') mf1.kernel(mo_coeff, mo_occ) mf.converged = mf1.converged mf.e_tot = mf1.e_tot mf.mo_energy = mf1.mo_energy mf.mo_coeff = mf1.mo_coeff mf.mo_occ = mf1.mo_occ # mf = copy.copy(mf) # def mf_kernel(*args, **kwargs): # logger.warn(mf, "fast_newton is a wrap function to quickly setup and call Newton solver. " # "There's no need to call kernel function again for fast_newton.") # del(mf.kernel) # warn once and remove circular depdence # return mf.e_tot # mf.kernel = mf_kernel return mf