def rotate_orb_cc(casscf, mo, fcasdm1, fcasdm2, eris, x0_guess=None, conv_tol_grad=1e-4, max_stepsize=None, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(casscf.stdout, casscf.verbose) if max_stepsize is None: max_stepsize = casscf.max_stepsize t3m = (time.clock(), time.time()) u = 1 g_orb, gorb_update, h_op, h_diag = \ casscf.gen_g_hop(mo, u, fcasdm1(), fcasdm2(), eris) g_kf0 = g_kf = g_orb norm_gkf0 = norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|=%5.3g', norm_gorb) t3m = log.timer('gen h_op', *t3m) def precond(x, e): if callable(h_diag): x = h_diag(x, e - casscf.ah_level_shift) else: hdiagd = h_diag - (e - casscf.ah_level_shift) hdiagd[abs(hdiagd) < 1e-8] = 1e-8 x = x / hdiagd norm_x = numpy.linalg.norm(x) x *= 1 / norm_x #if norm_x < 1e-2: # x *= 1e-2/norm_x return x # Dynamically increase the number of micro cycles when approach convergence? # if norm_gorb < 0.01: # max_cycle = casscf.max_cycle_micro_inner-int(numpy.log10(norm_gorb+1e-9)) # else: # max_cycle = casscf.max_cycle_micro_inner max_cycle = casscf.max_cycle_micro_inner dr = 0 jkcount = 0 norm_dr = 0 if x0_guess is None: x0_guess = g_orb ah_conv_tol = casscf.ah_conv_tol #ah_start_cycle = max(casscf.ah_start_cycle, int(-numpy.log10(norm_gorb))) ah_start_cycle = casscf.ah_start_cycle while True: # increase the AH accuracy when approach convergence ah_start_tol = min(norm_gorb * casscf.ah_grad_trust_region, casscf.ah_start_tol) log.debug1('Set ah_start_tol %g, ah_start_cycle %d, max_cycle %d', ah_start_tol, ah_start_cycle, max_cycle) g_orb0 = g_orb imic = 0 g_op = lambda: g_orb for ah_end, ihop, w, dxi, hdxi, residual, seig \ in iah.davidson_cc(h_op, g_op, precond, x0_guess, tol=ah_conv_tol, max_cycle=casscf.ah_max_cycle, lindep=casscf.ah_lindep, verbose=log): # residual = v[0] * (g+(h-e)x) ~ v[0] * grad norm_residual = numpy.linalg.norm(residual) if (ah_end or ihop == casscf.ah_max_cycle or # make sure to use the last step ((norm_residual < ah_start_tol) and (ihop >= ah_start_cycle)) or (seig < casscf.ah_lindep)): imic += 1 dxmax = numpy.max(abs(dxi)) if dxmax > max_stepsize: scale = max_stepsize / dxmax log.debug1('... scale rotation size %g', scale) dxi *= scale hdxi *= scale else: scale = None g_orb = g_orb + hdxi dr = dr + dxi norm_gorb0, norm_gorb = norm_gorb, numpy.linalg.norm(g_orb) norm_dxi = numpy.linalg.norm(dxi) norm_dr = numpy.linalg.norm(dr) log.debug( ' imic %d(%d) |g[o]|=%5.3g |dxi|=%5.3g ' 'max(|x|)=%5.3g |dr|=%5.3g eig=%5.3g seig=%5.3g', imic, ihop, norm_gorb, norm_dxi, dxmax, norm_dr, w, seig) if imic > 1 and norm_gorb > norm_gkf * casscf.ah_grad_trust_region: break elif (imic >= max_cycle or norm_gorb < conv_tol_grad * .3): break u = casscf.update_rotate_matrix(dr) jkcount += ihop gorb_update = h_op = h_diag = None t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) yield u, g_orb0, jkcount t3m = (time.clock(), time.time()) g_kf1, gorb_update, h_op, h_diag = \ casscf.gen_g_hop(mo, u, fcasdm1(), fcasdm2(), eris) g_kf1 = gorb_update(u, casscf.with_dep4) jkcount += 1 norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1 - g_orb) log.debug(' |g|=%5.3g (keyframe), |g-correction|=%5.3g', norm_gkf1, norm_dg) # # Special treatment if out of trust region # if (norm_dg > norm_gorb * casscf.ah_grad_trust_region and norm_gkf1 > norm_gkf and norm_gkf1 > norm_gkf0 * casscf.ah_grad_trust_region): log.debug( ' Keyframe |g|=%5.3g |g_last| =%5.3g out of trust region', norm_gkf1, norm_gorb) if ((not casscf.with_dep4 and norm_gkf > 5e-4) or (hasattr(casscf._scf, 'with_df') and casscf._scf.with_df) or isinstance(casscf._scf, scf.uhf.UHF)): #TODO: transformation for DF integrals u = casscf.update_rotate_matrix(dr - dxi) yield u, g_kf - hdxi, jkcount break else: g_kf1 = gorb_update(u, True) jkcount += 1 norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1 - g_orb) log.debug( 'With dep4 |g|=%5.3g (keyframe), |g-correction|=%5.3g', norm_gkf1, norm_dg) t3m = log.timer('gen h_op', *t3m) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 x0_guess = dxi ah_start_cycle -= 1
def rotate_orb_cc(mf, mo_coeff, mo_occ, fock_ao, h1e, conv_tol_grad=None, verbose=None): from pyscf.scf import iah if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(mf.conv_tol*.1) t2m = (time.clock(), time.time()) if isinstance(mo_coeff, numpy.ndarray) and mo_coeff.ndim == 2: nmo = mo_coeff.shape[1] else: nmo = mo_coeff[0].shape[1] g_orb, h_op, h_diag = mf.gen_g_hop(mo_coeff, mo_occ, fock_ao) g_kf = g_orb norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|= %4.3g (keyframe)', norm_gorb) t3m = log.timer('gen h_op', *t2m) def precond(x, e): hdiagd = h_diag-(e-mf.ah_level_shift) hdiagd[abs(hdiagd)<1e-8] = 1e-8 x = x/hdiagd ## Because of DFT, donot norm to 1 which leads 1st DM too large. # norm_x = numpy.linalg.norm(x) # if norm_x < 1e-2: # x *= 1e-2/norm_x return x kf_compensate = 0 kf_trust_region = 0.25 g_op = lambda: g_orb x0_guess = g_orb while True: ah_conv_tol = min(norm_gorb**2, mf.ah_conv_tol) # increase the AH accuracy when approach convergence ah_start_tol = min(norm_gorb*5, mf.ah_start_tol) #ah_start_cycle = max(mf.ah_start_cycle, int(-numpy.log10(norm_gorb))) ah_start_cycle = mf.ah_start_cycle g_orb0 = g_orb imic = 0 dr = 0 jkcount = 0 ikf = 0 dm0 = mf.make_rdm1(mo_coeff, mo_occ) vhf0 = fock_ao - h1e for ah_end, ihop, w, dxi, hdxi, residual, seig \ in iah.davidson_cc(h_op, g_op, precond, x0_guess, tol=ah_conv_tol, max_cycle=mf.ah_max_cycle, lindep=mf.ah_lindep, verbose=log): norm_residual = numpy.linalg.norm(residual) if (ah_end or ihop == mf.ah_max_cycle or # make sure to use the last step ((norm_residual < ah_start_tol) and (ihop >= ah_start_cycle)) or (seig < mf.ah_lindep)): imic += 1 dxmax = numpy.max(abs(dxi)) if dxmax > mf.max_stepsize * max(1,norm_gorb): scale = mf.max_stepsize * max(1,norm_gorb) / dxmax log.debug1('... scale rotation size %g', scale) dxi *= scale hdxi *= scale else: scale = None dr = dr + dxi g_orb = g_orb + hdxi norm_dr = numpy.linalg.norm(dr) norm_gorb = numpy.linalg.norm(g_orb) norm_dxi = numpy.linalg.norm(dxi) log.debug(' imic %d(%d) |g|= %4.3g |dxi|= %4.3g ' 'max(|x|)= %4.3g |dr|= %4.3g eig= %4.3g seig= %4.3g', imic, ihop, norm_gorb, norm_dxi, dxmax, norm_dr, w, seig) max_cycle = mf.max_cycle_inner-int(numpy.log(norm_gkf+1e-9)*2) log.debug1('Set ah_start_tol %g, ah_start_cycle %d, max_cycle %d', ah_start_tol, ah_start_cycle, max_cycle) ikf += 1 if imic > 3 and norm_gorb > norm_gkf*mf.ah_grad_trust_region: g_orb = g_orb - hdxi dr = dr - dxi norm_gorb = numpy.linalg.norm(g_orb) log.debug('|g| >> keyframe, Restore previouse step') break elif (imic >= max_cycle or norm_gorb < conv_tol_grad*.5): break elif (ikf > 2 and # avoid frequent keyframe (ikf > (mf.keyframe_interval - kf_compensate -numpy.log(norm_dr)*mf.keyframe_interval_rate) or norm_gorb < norm_gkf*kf_trust_region)): ikf = 0 u = mf.update_rotate_matrix(dr, mo_occ) mo1 = mf.rotate_mo(mo_coeff, u) dm = mf.make_rdm1(mo1, mo_occ) # use mf._scf.get_veff to avoid density-fit mf polluting get_veff vhf0 = mf._scf.get_veff(mf._scf.mol, dm, dm_last=dm0, vhf_last=vhf0) dm0 = dm g_kf1 = mf.get_grad(mo1, mo_occ, h1e+vhf0) norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1-g_orb) jkcount += 1 log.debug('Adjust keyframe g_orb to |g|= %4.3g ' '|g-correction|= %4.3g', norm_gkf1, norm_dg) # kf_compensate: If the keyframe and the esitimated g_orb are too different, # insert more keyframes for the following optimization kf_compensate = norm_dg / norm_gorb if (kf_compensate > mf.ah_grad_trust_region and norm_gkf1 > norm_gkf and # More iters when close to local minimum norm_gkf1 > conv_tol_grad*mf.ah_grad_trust_region): g_orb = g_orb - hdxi dr = dr - dxi norm_gorb = numpy.linalg.norm(g_orb) log.debug('Out of trust region. Restore previouse step') break else: kf_trust_region = max(min(kf_compensate, 0.25), .05) log.debug1('... kf_compensate = %g kf_trust_region = %g', kf_compensate, kf_trust_region) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 u = mf.update_rotate_matrix(dr, mo_occ) jkcount += ihop + 1 log.debug(' tot inner=%d %d JK |g|= %4.3g |u-1|= %4.3g', imic, jkcount, norm_gorb, numpy.linalg.norm(u-numpy.eye(nmo))) h_op = h_diag = None t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) mo_coeff, mo_occ, fock_ao = (yield u, g_kf, jkcount) g_kf, h_op, h_diag = mf.gen_g_hop(mo_coeff, mo_occ, fock_ao) norm_gkf = numpy.linalg.norm(g_kf) norm_dg = numpy.linalg.norm(g_kf-g_orb) log.debug(' |g|= %4.3g (keyframe), |g-correction|= %4.3g', norm_gkf, norm_dg) kf_compensate = norm_dg / norm_gorb kf_trust_region = max(min(kf_compensate, 0.25), .05) log.debug1('... kf_compensate = %g kf_trust_region = %g', kf_compensate, kf_trust_region) g_orb = g_kf norm_gorb = norm_gkf x0_guess = dxi
def rotate_orb_cc(mf, mo_coeff, mo_occ, fock_ao, h1e, conv_tol_grad=None, verbose=None): from pyscf.scf import iah if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(mf.conv_tol * .1) t2m = (time.clock(), time.time()) if isinstance(mo_coeff, numpy.ndarray) and mo_coeff.ndim == 2: nmo = mo_coeff.shape[1] else: nmo = mo_coeff[0].shape[1] g_orb, h_op, h_diag = mf.gen_g_hop(mo_coeff, mo_occ, fock_ao) g_kf = g_orb norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|= %4.3g (keyframe)', norm_gorb) t3m = log.timer('gen h_op', *t2m) def precond(x, e): hdiagd = h_diag - (e - mf.ah_level_shift) hdiagd[abs(hdiagd) < 1e-8] = 1e-8 x = x / hdiagd ## Because of DFT, donot norm to 1 which leads 1st DM too large. # norm_x = numpy.linalg.norm(x) # if norm_x < 1e-2: # x *= 1e-2/norm_x return x kf_compensate = 0 kf_trust_region = 0.25 g_op = lambda: g_orb x0_guess = g_orb while True: ah_conv_tol = min(norm_gorb**2, mf.ah_conv_tol) # increase the AH accuracy when approach convergence ah_start_tol = min(norm_gorb * 5, mf.ah_start_tol) #ah_start_cycle = max(mf.ah_start_cycle, int(-numpy.log10(norm_gorb))) ah_start_cycle = mf.ah_start_cycle g_orb0 = g_orb imic = 0 dr = 0 jkcount = 0 ikf = 0 dm0 = mf.make_rdm1(mo_coeff, mo_occ) vhf0 = fock_ao - h1e for ah_end, ihop, w, dxi, hdxi, residual, seig \ in iah.davidson_cc(h_op, g_op, precond, x0_guess, tol=ah_conv_tol, max_cycle=mf.ah_max_cycle, lindep=mf.ah_lindep, verbose=log): norm_residual = numpy.linalg.norm(residual) if (ah_end or ihop == mf.ah_max_cycle or # make sure to use the last step ((norm_residual < ah_start_tol) and (ihop >= ah_start_cycle)) or (seig < mf.ah_lindep)): imic += 1 dxmax = numpy.max(abs(dxi)) if dxmax > mf.max_stepsize * max(1, norm_gorb): scale = mf.max_stepsize * max(1, norm_gorb) / dxmax log.debug1('... scale rotation size %g', scale) dxi *= scale hdxi *= scale else: scale = None dr = dr + dxi g_orb = g_orb + hdxi norm_dr = numpy.linalg.norm(dr) norm_gorb = numpy.linalg.norm(g_orb) norm_dxi = numpy.linalg.norm(dxi) log.debug( ' imic %d(%d) |g|= %4.3g |dxi|= %4.3g ' 'max(|x|)= %4.3g |dr|= %4.3g eig= %4.3g seig= %4.3g', imic, ihop, norm_gorb, norm_dxi, dxmax, norm_dr, w, seig) max_cycle = mf.max_cycle_inner - int( numpy.log(norm_gkf + 1e-9) * 2) log.debug1( 'Set ah_start_tol %g, ah_start_cycle %d, max_cycle %d', ah_start_tol, ah_start_cycle, max_cycle) ikf += 1 if imic > 3 and norm_gorb > norm_gkf * mf.ah_grad_trust_region: g_orb = g_orb - hdxi dr = dr - dxi norm_gorb = numpy.linalg.norm(g_orb) log.debug('|g| >> keyframe, Restore previouse step') break elif (imic >= max_cycle or norm_gorb < conv_tol_grad * .5): break elif (ikf > 2 and # avoid frequent keyframe (ikf > (mf.keyframe_interval - kf_compensate - numpy.log(norm_dr) * mf.keyframe_interval_rate) or norm_gorb < norm_gkf * kf_trust_region)): ikf = 0 u = mf.update_rotate_matrix(dr, mo_occ) mo1 = mf.rotate_mo(mo_coeff, u) dm = mf.make_rdm1(mo1, mo_occ) # use mf._scf.get_veff to avoid density-fit mf polluting get_veff vhf0 = mf._scf.get_veff(mf._scf.mol, dm, dm_last=dm0, vhf_last=vhf0) dm0 = dm g_kf1 = mf.get_grad(mo1, mo_occ, h1e + vhf0) norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1 - g_orb) jkcount += 1 log.debug( 'Adjust keyframe g_orb to |g|= %4.3g ' '|g-correction|= %4.3g', norm_gkf1, norm_dg) # kf_compensate: If the keyframe and the esitimated g_orb are too different, # insert more keyframes for the following optimization kf_compensate = norm_dg / norm_gorb if (kf_compensate > mf.ah_grad_trust_region and norm_gkf1 > norm_gkf and # More iters when close to local minimum norm_gkf1 > conv_tol_grad * mf.ah_grad_trust_region): g_orb = g_orb - hdxi dr = dr - dxi norm_gorb = numpy.linalg.norm(g_orb) log.debug( 'Out of trust region. Restore previouse step') break else: kf_trust_region = max(min(kf_compensate, 0.25), .05) log.debug1( '... kf_compensate = %g kf_trust_region = %g', kf_compensate, kf_trust_region) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 u = mf.update_rotate_matrix(dr, mo_occ) jkcount += ihop + 1 log.debug(' tot inner=%d %d JK |g|= %4.3g |u-1|= %4.3g', imic, jkcount, norm_gorb, numpy.linalg.norm(u - numpy.eye(nmo))) h_op = h_diag = None t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) mo_coeff, mo_occ, fock_ao = (yield u, g_kf, jkcount) g_kf, h_op, h_diag = mf.gen_g_hop(mo_coeff, mo_occ, fock_ao) norm_gkf = numpy.linalg.norm(g_kf) norm_dg = numpy.linalg.norm(g_kf - g_orb) log.debug(' |g|= %4.3g (keyframe), |g-correction|= %4.3g', norm_gkf, norm_dg) kf_compensate = norm_dg / norm_gorb kf_trust_region = max(min(kf_compensate, 0.25), .05) log.debug1('... kf_compensate = %g kf_trust_region = %g', kf_compensate, kf_trust_region) g_orb = g_kf norm_gorb = norm_gkf x0_guess = dxi
def rotate_orb_cc(casscf, mo, fcasdm1, fcasdm2, eris, x0_guess=None, conv_tol_grad=1e-4, max_stepsize=None, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(casscf.stdout, casscf.verbose) if max_stepsize is None: max_stepsize = casscf.max_stepsize t3m = (time.clock(), time.time()) u = 1 g_orb, gorb_update, h_op, h_diag = \ casscf.gen_g_hop(mo, u, fcasdm1(), fcasdm2(), eris) g_kf0 = g_kf = g_orb norm_gkf0 = norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|=%5.3g', norm_gorb) t3m = log.timer('gen h_op', *t3m) def precond(x, e): if callable(h_diag): x = h_diag(x, e-casscf.ah_level_shift) else: hdiagd = h_diag-(e-casscf.ah_level_shift) hdiagd[abs(hdiagd)<1e-8] = 1e-8 x = x/hdiagd norm_x = numpy.linalg.norm(x) x *= 1/norm_x #if norm_x < 1e-2: # x *= 1e-2/norm_x return x # Dynamically increase the number of micro cycles when approach convergence? # if norm_gorb < 0.01: # max_cycle = casscf.max_cycle_micro_inner-int(numpy.log10(norm_gorb+1e-9)) # else: # max_cycle = casscf.max_cycle_micro_inner max_cycle = casscf.max_cycle_micro_inner dr = 0 jkcount = 0 norm_dr = 0 if x0_guess is None: x0_guess = g_orb ah_conv_tol = casscf.ah_conv_tol #ah_start_cycle = max(casscf.ah_start_cycle, int(-numpy.log10(norm_gorb))) ah_start_cycle = casscf.ah_start_cycle while True: # increase the AH accuracy when approach convergence ah_start_tol = min(norm_gorb*casscf.ah_grad_trust_region, casscf.ah_start_tol) log.debug1('Set ah_start_tol %g, ah_start_cycle %d, max_cycle %d', ah_start_tol, ah_start_cycle, max_cycle) g_orb0 = g_orb imic = 0 g_op = lambda: g_orb for ah_end, ihop, w, dxi, hdxi, residual, seig \ in iah.davidson_cc(h_op, g_op, precond, x0_guess, tol=ah_conv_tol, max_cycle=casscf.ah_max_cycle, lindep=casscf.ah_lindep, verbose=log): # residual = v[0] * (g+(h-e)x) ~ v[0] * grad norm_residual = numpy.linalg.norm(residual) if (ah_end or ihop == casscf.ah_max_cycle or # make sure to use the last step ((norm_residual < ah_start_tol) and (ihop >= ah_start_cycle)) or (seig < casscf.ah_lindep)): imic += 1 dxmax = numpy.max(abs(dxi)) if dxmax > max_stepsize: scale = max_stepsize / dxmax log.debug1('... scale rotation size %g', scale) dxi *= scale hdxi *= scale else: scale = None g_orb = g_orb + hdxi dr = dr + dxi norm_gorb0, norm_gorb = norm_gorb, numpy.linalg.norm(g_orb) norm_dxi = numpy.linalg.norm(dxi) norm_dr = numpy.linalg.norm(dr) log.debug(' imic %d(%d) |g[o]|=%5.3g |dxi|=%5.3g ' 'max(|x|)=%5.3g |dr|=%5.3g eig=%5.3g seig=%5.3g', imic, ihop, norm_gorb, norm_dxi, dxmax, norm_dr, w, seig) if imic > 1 and norm_gorb > norm_gkf*casscf.ah_grad_trust_region: break elif (imic >= max_cycle or norm_gorb < conv_tol_grad*.3): break u = casscf.update_rotate_matrix(dr) jkcount += ihop gorb_update = h_op = h_diag = None t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) yield u, g_orb0, jkcount t3m = (time.clock(), time.time()) g_kf1, gorb_update, h_op, h_diag = \ casscf.gen_g_hop(mo, u, fcasdm1(), fcasdm2(), eris) g_kf1 = gorb_update(u, casscf.with_dep4) jkcount += 1 norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1-g_orb) log.debug(' |g|=%5.3g (keyframe), |g-correction|=%5.3g', norm_gkf1, norm_dg) # # Special treatment if out of trust region # if (norm_dg > norm_gorb*casscf.ah_grad_trust_region and norm_gkf1 > norm_gkf and norm_gkf1 > norm_gkf0*casscf.ah_grad_trust_region): log.debug(' Keyframe |g|=%5.3g |g_last| =%5.3g out of trust region', norm_gkf1, norm_gorb) if ((not casscf.with_dep4 and norm_gkf > 5e-4) or (hasattr(casscf._scf, 'with_df') and casscf._scf.with_df) or isinstance(casscf._scf, scf.uhf.UHF)): #TODO: transformation for DF integrals u = casscf.update_rotate_matrix(dr-dxi) yield u, g_kf-hdxi, jkcount break else: g_kf1 = gorb_update(u, True) jkcount += 1 norm_gkf1 = numpy.linalg.norm(g_kf1) norm_dg = numpy.linalg.norm(g_kf1-g_orb) log.debug('With dep4 |g|=%5.3g (keyframe), |g-correction|=%5.3g', norm_gkf1, norm_dg) t3m = log.timer('gen h_op', *t3m) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 x0_guess = dxi ah_start_cycle -= 1