Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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