def update_orb_ci(casscf, mo, ci0, eris, x0_guess=None, conv_tol_grad=1e-4, max_stepsize=None, verbose=None): log = logger.new_logger(casscf, verbose) if max_stepsize is None: max_stepsize = casscf.max_stepsize nmo = mo.shape[1] ci0 = ci0.ravel() g_all, g_update, h_op, h_diag = gen_g_hop(casscf, mo, ci0, eris) ngorb = g_all.size - ci0.size g_kf = g_all norm_gkf = norm_gall = numpy.linalg.norm(g_all) log.debug(' |g|=%5.3g (%4.3g %4.3g) (keyframe)', norm_gall, numpy.linalg.norm(g_all[:ngorb]), numpy.linalg.norm(g_all[ngorb:])) 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 x *= 1/numpy.linalg.norm(x) return x def scale_down_step(dxi, hdxi): dxmax = abs(dxi).max() if dxmax > casscf.max_stepsize: scale = casscf.max_stepsize / dxmax log.debug1('Scale rotation by %g', scale) dxi *= scale hdxi *= scale return dxi, hdxi class Statistic: def __init__(self): self.imic = 0 self.tot_hop = 0 self.tot_kf = 1 # The call to gen_g_hop if x0_guess is None: x0_guess = g_all g_op = lambda: g_all stat = Statistic() dr = 0 ikf = 0 u = numpy.eye(nmo) ci_kf = ci0 if norm_gall < conv_tol_grad*.3: return u, ci_kf, norm_gall, stat, x0_guess for ah_conv, ihop, w, dxi, hdxi, residual, seig \ in ciah.davidson_cc(h_op, g_op, precond, x0_guess, tol=casscf.ah_conv_tol, max_cycle=casscf.ah_max_cycle, lindep=casscf.ah_lindep, verbose=log): stat.tot_hop = ihop norm_residual = numpy.linalg.norm(residual) if (ah_conv or ihop == casscf.ah_max_cycle or # make sure to use the last step ((norm_residual < casscf.ah_start_tol) and (ihop >= casscf.ah_start_cycle)) or (seig < casscf.ah_lindep)): stat.imic += 1 dxmax = abs(dxi).max() dxi, hdxi = scale_down_step(dxi, hdxi) dr += dxi g_all = g_all + hdxi norm_dr = numpy.linalg.norm(dr) norm_gall = numpy.linalg.norm(g_all) norm_gorb = numpy.linalg.norm(g_all[:ngorb]) norm_gci = numpy.linalg.norm(g_all[ngorb:]) log.debug(' imic %d(%d) |g|=%3.2e (%2.1e %2.1e) |dxi|=%3.2e ' 'max(x)=%3.2e |dr|=%3.2e eig=%2.1e seig=%2.1e', stat.imic, ihop, norm_gall, norm_gorb, norm_gci, numpy.linalg.norm(dxi), dxmax, norm_dr, w, seig) max_cycle = max(casscf.max_cycle_micro, casscf.max_cycle_micro-int(numpy.log(norm_gkf+1e-7)*2)) log.debug1('Set max_cycle %d', max_cycle) ikf += 1 if stat.imic > 3 and norm_gall > norm_gkf*casscf.ah_trust_region: g_all = g_all - hdxi dr -= dxi norm_gall = numpy.linalg.norm(g_all) log.debug('|g| >> keyframe, Restore previouse step') break elif (stat.imic >= max_cycle or norm_gall < conv_tol_grad*.3): break elif ((ikf >= max(casscf.kf_interval, casscf.kf_interval-numpy.log(norm_dr+1e-7)) or # Insert keyframe if the keyframe and the esitimated grad are too different norm_gall < norm_gkf/casscf.kf_trust_region)): ikf = 0 u, ci_kf = extract_rotation(casscf, dr, u, ci_kf) dr[:] = 0 g_kf1 = g_update(u, ci_kf) stat.tot_kf += 1 norm_gkf1 = numpy.linalg.norm(g_kf1) norm_gorb = numpy.linalg.norm(g_kf1[:ngorb]) norm_gci = numpy.linalg.norm(g_kf1[ngorb:]) norm_dg = numpy.linalg.norm(g_kf1-g_all) log.debug('Adjust keyframe to |g|= %4.3g (%4.3g %4.3g) ' '|g-correction|= %4.3g', norm_gkf1, norm_gorb, norm_gci, norm_dg) if (norm_dg < norm_gall*casscf.ah_trust_region # kf not too diff #or norm_gkf1 < norm_gkf # grad is decaying # close to solution or norm_gkf1 < conv_tol_grad*casscf.ah_trust_region): g_all = g_kf = g_kf1 g_kf1 = None norm_gall = norm_gkf = norm_gkf1 else: g_all = g_all - hdxi dr -= dxi norm_gall = norm_gkf = numpy.linalg.norm(g_all) log.debug('Out of trust region. Restore previouse step') break u, ci_kf = extract_rotation(casscf, dr, u, ci_kf) log.debug(' tot inner=%d |g|= %4.3g (%4.3g %4.3g) |u-1|= %4.3g |dci|= %4.3g', stat.imic, norm_gall, norm_gorb, norm_gci, numpy.linalg.norm(u-numpy.eye(nmo)), numpy.linalg.norm(ci_kf-ci0)) return u, ci_kf, norm_gkf, stat, dxi
def rotate_orb_cc(mf, mo_coeff, mo_occ, fock_ao, h1e, conv_tol_grad=None, verbose=None): from pyscf.scf import ciah 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_trust_region = mf.kf_trust_region 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 ciah.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: scale = mf.max_stepsize / 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 = max( mf.max_cycle_inner, 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 #TODO: replace it with keyframe_scheduler ( ikf >= max(mf.kf_interval, mf.kf_interval - numpy.log(norm_dr + 1e-9)) or # Insert keyframe if the keyframe and the esitimated g_orb are too different 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) if (norm_dg < norm_gorb * mf.ah_grad_trust_region # kf not too diff #or norm_gkf1 < norm_gkf # grad is decaying # close to solution or norm_gkf1 < conv_tol_grad * mf.ah_grad_trust_region): kf_trust_region = min( max(norm_gorb / (norm_dg + 1e-9), mf.kf_trust_region), 10) log.debug1('Set kf_trust_region = %g', kf_trust_region) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 else: 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 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_trust_region = min( max(norm_gorb / (norm_dg + 1e-9), mf.kf_trust_region), 10) log.debug1('Set kf_trust_region = %g', kf_trust_region) g_orb = g_kf norm_gorb = norm_gkf x0_guess = dxi
def rotate_orb_cc(casscf, mo, fcivec, fcasdm1, fcasdm2, eris, x0_guess=None, conv_tol_grad=1e-4, max_stepsize=None, verbose=None): log = logger.new_logger(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) ngorb = g_orb.size g_kf = g_orb norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|=%5.3g', norm_gorb) t3m = log.timer('gen h_op', *t3m) if norm_gorb < conv_tol_grad * .3: u = casscf.update_rotate_matrix(g_orb * 0) yield u, g_orb, 1, x0_guess return def precond(x, e): 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 jkcount = 0 if x0_guess is None: x0_guess = g_orb imic = 0 dr = 0 ikf = 0 g_op = lambda: g_orb for ah_end, ihop, w, dxi, hdxi, residual, seig \ in ciah.davidson_cc(h_op, g_op, precond, x0_guess, tol=casscf.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 < casscf.ah_start_tol) and (ihop >= casscf.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_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) ikf += 1 if ikf > 1 and norm_gorb > norm_gkf * casscf.ah_grad_trust_region: g_orb = g_orb - hdxi dr -= dxi #norm_gorb = numpy.linalg.norm(g_orb) log.debug('|g| >> keyframe, Restore previouse step') break elif (norm_gorb < conv_tol_grad * .3): break elif (ikf >= max(casscf.kf_interval, -numpy.log(norm_dr + 1e-7)) or # Insert keyframe if the keyframe and the esitimated grad are too different norm_gorb < norm_gkf / casscf.kf_trust_region): ikf = 0 u = casscf.update_rotate_matrix(dr, u) t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) yield u, g_kf, ihop + jkcount, dxi 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) g_kf1 = gorb_update(u, fcivec()) 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_gkf * casscf.ah_grad_trust_region): log.debug( ' Keyframe |g|=%5.3g |g_last| =%5.3g out of trust region', norm_gkf1, norm_gorb) dr = -dxi g_kf = g_kf1 - hdxi break t3m = log.timer('gen h_op', *t3m) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 dr[:] = 0 u = casscf.update_rotate_matrix(dr, u) yield u, g_kf, ihop + jkcount, 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 ciah.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 ciah 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_trust_region = mf.kf_trust_region 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 ciah.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: scale = mf.max_stepsize / 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 = max(mf.max_cycle_inner, 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 #TODO: replace it with keyframe_scheduler (ikf >= max(mf.kf_interval, mf.kf_interval-numpy.log(norm_dr+1e-9)) or # Insert keyframe if the keyframe and the esitimated g_orb are too different 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) if (norm_dg < norm_gorb*mf.ah_grad_trust_region # kf not too diff #or norm_gkf1 < norm_gkf # grad is decaying # close to solution or norm_gkf1 < conv_tol_grad*mf.ah_grad_trust_region): kf_trust_region = min(max(norm_gorb/(norm_dg+1e-9), mf.kf_trust_region), 10) log.debug1('Set kf_trust_region = %g', kf_trust_region) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 else: 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 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_trust_region = min(max(norm_gorb/(norm_dg+1e-9), mf.kf_trust_region), 10) log.debug1('Set kf_trust_region = %g', kf_trust_region) g_orb = g_kf norm_gorb = norm_gkf x0_guess = dxi
def rotate_orb_cc(casscf, mo, fcivec, fcasdm1, fcasdm2, eris, x0_guess=None, conv_tol_grad=1e-4, max_stepsize=None, verbose=None): log = logger.new_logger(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) ngorb = g_orb.size g_kf = g_orb norm_gkf = norm_gorb = numpy.linalg.norm(g_orb) log.debug(' |g|=%5.3g', norm_gorb) t3m = log.timer('gen h_op', *t3m) if norm_gorb < conv_tol_grad * .3: u = casscf.update_rotate_matrix(g_orb * 0) yield u, g_orb, 1, x0_guess return def precond(x, e): 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 jkcount = 0 if x0_guess is None: x0_guess = g_orb imic = 0 dr = 0 ikf = 0 g_op = lambda: g_orb for ah_end, ihop, w, dxi, hdxi, residual, seig \ in ciah.davidson_cc(h_op, g_op, precond, x0_guess, tol=casscf.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 < casscf.ah_start_tol) and (ihop >= casscf.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_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) ikf += 1 if ikf > 1 and norm_gorb > norm_gkf * casscf.ah_grad_trust_region: g_orb = g_orb - hdxi dr -= dxi #norm_gorb = numpy.linalg.norm(g_orb) log.debug('|g| >> keyframe, Restore previouse step') break elif (norm_gorb < conv_tol_grad * .3): break elif (ikf >= max(casscf.kf_interval, -numpy.log(norm_dr + 1e-7)) or # Insert keyframe if the keyframe and the esitimated grad are too different norm_gorb < norm_gkf / casscf.kf_trust_region): ikf = 0 u = casscf.update_rotate_matrix(dr, u) t3m = log.timer('aug_hess in %d inner iters' % imic, *t3m) yield u, g_kf, ihop + jkcount, dxi t3m = (time.clock(), time.time()) # TODO: test whether to update h_op, h_diag to change the orbital hessian. # It leads to the different hessian operations in the same davidson # diagonalization procedure. This is generally a bad approximation because it # results in ill-defined hessian eigenvalue in the davidson algorithm. But in # certain cases, it is a small perturbation that help the mcscf optimization # algorithm move out of local minimum # h_op, h_diag = \ # casscf.gen_g_hop(mo, u, fcasdm1(), fcasdm2(), eris)[2:4] g_kf1 = gorb_update(u, fcivec()) 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_gkf * casscf.ah_grad_trust_region): log.debug( ' Keyframe |g|=%5.3g |g_last| =%5.3g out of trust region', norm_gkf1, norm_gorb) # Slightly moving forward, not completely restoring last step. # In some cases, the optimization moves out of trust region in the first micro # iteration. The small forward step can ensure the orbital changes in the # current iteration. dr = -dxi * .5 g_kf = g_kf1 break t3m = log.timer('gen h_op', *t3m) g_orb = g_kf = g_kf1 norm_gorb = norm_gkf = norm_gkf1 dr[:] = 0 u = casscf.update_rotate_matrix(dr, u) yield u, g_kf, ihop + jkcount, dxi