Ejemplo n.º 1
0
 def test_orth_ao(self):
     c0 = orth.pre_orth_ao(mol, method='scf')
     self.assertAlmostEqual(numpy.linalg.norm(c0), 5.7742626195362039, 9)
     self.assertAlmostEqual(abs(c0).sum(), 33.461490657433551, 8)
     c = orth.orth_ao(mol, 'lowdin', c0)
     self.assertAlmostEqual(numpy.linalg.norm(c), 8.9823854843222257, 9)
     self.assertAlmostEqual(abs(c).sum(), 94.933979307106767, 8)
     c = orth.orth_ao(mol, 'meta_lowdin', c0)
     self.assertAlmostEqual(numpy.linalg.norm(c), 8.9823854843222257, 9)
     self.assertAlmostEqual(abs(c).sum(), 93.029386338534394, 8)
Ejemplo n.º 2
0
 def test_orth_ao(self):
     c0 = orth.pre_orth_ao(mol, method='scf')
     self.assertAlmostEqual(numpy.linalg.norm(c0), 7.2617698799320358, 9)
     self.assertAlmostEqual(abs(c0).sum(), 40.116080631662804, 8)
     c = orth.orth_ao(mol, 'lowdin', c0)
     self.assertAlmostEqual(numpy.linalg.norm(c), 10.967144073462256, 9)
     self.assertAlmostEqual(abs(c).sum(), 112.23459140302003, 8)
     c = orth.orth_ao(mol, 'meta_lowdin', c0)
     self.assertAlmostEqual(numpy.linalg.norm(c), 10.967144073462256, 9)
     self.assertAlmostEqual(abs(c).sum(), 111.61017124719302, 8)
Ejemplo n.º 3
0
def analyze(mf, verbose=logger.DEBUG, **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, verbose)

    log.note('**** MO energy ****')
    if mf._focka_ao is None:
        for i,c in enumerate(mo_occ):
            log.note('MO #%-3d energy= %-18.15g occ= %g', i+1, mo_energy[i], c)
    else:
        mo_ea = numpy.einsum('ik,ik->k', mo_coeff, mf._focka_ao.dot(mo_coeff))
        mo_eb = numpy.einsum('ik,ik->k', mo_coeff, mf._fockb_ao.dot(mo_coeff))
        log.note('                Roothaan           | alpha              | beta')
        for i,c in enumerate(mo_occ):
            log.note('MO #%-3d energy= %-18.15g | %-18.15g | %-18.15g occ= %g',
                     i+1, mo_energy[i], mo_ea[i], mo_eb[i], c)
    ovlp_ao = mf.get_ovlp()
    if verbose >= logger.DEBUG:
        log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
        label = mf.mol.spheric_labels(True)
        orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
        c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
        dump_mat.dump_rec(mf.stdout, c, label, start=1, **kwargs)
    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return mf.mulliken_meta(mf.mol, dm, s=s, verbose=log)
Ejemplo n.º 4
0
Archivo: hf.py Proyecto: pengdl/pyscf
def analyze(mf, verbose=logger.DEBUG):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis; Diople moment.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, verbose)

    log.note('**** MO energy ****')
    for i,c in enumerate(mo_occ):
        log.note('MO #%-3d energy= %-18.15g occ= %g', i+1, mo_energy[i], c)
    ovlp_ao = mf.get_ovlp()
    if verbose >= logger.DEBUG:
        log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
        label = mf.mol.spheric_labels(True)
        orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
        c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
        dump_mat.dump_rec(mf.stdout, c, label, start=1)
    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return (mf.mulliken_meta(mf.mol, dm, s=ovlp_ao, verbose=log),
            mf.dip_moment(mf.mol, dm, verbose=log))
Ejemplo n.º 5
0
def mulliken_meta(cell, dm_ao_kpts, verbose=logger.DEBUG,
                  pre_orth_method=PRE_ORTH_METHOD, s=None):
    '''A modified Mulliken population analysis, based on meta-Lowdin AOs.

    Note this function only computes the Mulliken population for the gamma
    point density matrix.
    '''
    from pyscf.lo import orth
    if s is None:
        s = khf.get_ovlp(cell)
    log = logger.new_logger(cell, verbose)
    log.note('Analyze output for *gamma point*.')
    log.info('    To include the contributions from k-points, transform to a '
             'supercell then run the population analysis on the supercell\n'
             '        from pyscf.pbc.tools import k2gamma\n'
             '        k2gamma.k2gamma(mf).mulliken_meta()')
    log.note("KUHF mulliken_meta")
    dm_ao_gamma = dm_ao_kpts[:,0,:,:].real
    s_gamma = s[0,:,:].real
    c = orth.restore_ao_character(cell, pre_orth_method)
    orth_coeff = orth.orth_ao(cell, 'meta_lowdin', pre_orth_ao=c, s=s_gamma)
    c_inv = np.dot(orth_coeff.T, s_gamma)
    dm_a = reduce(np.dot, (c_inv, dm_ao_gamma[0], c_inv.T.conj()))
    dm_b = reduce(np.dot, (c_inv, dm_ao_gamma[1], c_inv.T.conj()))

    log.note(' ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **')
    return mol_uhf.mulliken_pop(cell, (dm_a,dm_b), np.eye(orth_coeff.shape[0]), log)
Ejemplo n.º 6
0
def atomic_init_guess(mol, mo_coeff):
    s = mol.intor_symmetric('int1e_ovlp')
    c = orth.orth_ao(mol, s=s)
    mo = reduce(numpy.dot, (c.conj().T, s, mo_coeff))
    nmo = mo_coeff.shape[1]
# Find the AOs which have largest overlap to MOs
    idx = numpy.argsort(numpy.einsum('pi,pi->p', mo.conj(), mo))
    nmo = mo.shape[1]
    idx = idx[-nmo:]
    u, w, vh = numpy.linalg.svd(mo[idx])
    return lib.dot(vh, u.conj().T)
Ejemplo n.º 7
0
 def test_ghost_atm_meta_lowdin(self):
     mol = gto.Mole()
     mol.atom = [["O" , (0. , 0.     , 0.)],
                 ['ghost'   , (0. , -0.757, 0.587)],
                 [1   , (0. , 0.757 , 0.587)] ]
     mol.spin = 1
     mol.basis = {'O':'ccpvdz', 'H':'ccpvdz',
                  'GHOST': gto.basis.load('631g','H')}
     mol.build()
     c = orth.orth_ao(mol, method='meta_lowdin')
     self.assertAlmostEqual(numpy.linalg.norm(c), 7.9067188905237256, 9)
Ejemplo n.º 8
0
def analyze(mf, verbose=logger.DEBUG, **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Occupancy for each irreps; Mulliken population analysis
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mol = mf.mol
    if not mol.symmetry:
        return hf.analyze(mf, verbose, **kwargs)

    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    log = logger.Logger(mf.stdout, verbose)
    nirrep = len(mol.irrep_id)
    ovlp_ao = mf.get_ovlp()
    orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff,
                                 s=ovlp_ao, check=False)
    orbsym = numpy.array(orbsym)
    wfnsym = 0
    noccs = [sum(orbsym[mo_occ>0]==ir) for ir in mol.irrep_id]
    log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym))
    log.note('occupancy for each irrep:  ' + (' %4s'*nirrep), *mol.irrep_name)
    log.note('double occ                 ' + (' %4d'*nirrep), *noccs)
    log.note('**** MO energy ****')
    irname_full = {}
    for k,ir in enumerate(mol.irrep_id):
        irname_full[ir] = mol.irrep_name[k]
    irorbcnt = {}
    for k, j in enumerate(orbsym):
        if j in irorbcnt:
            irorbcnt[j] += 1
        else:
            irorbcnt[j] = 1
        log.note('MO #%d (%s #%d), energy= %.15g occ= %g',
                 k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k])

    if verbose >= logger.DEBUG:
        label = mol.spheric_labels(True)
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsym):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
        log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
        orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
        c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
        dump_mat.dump_rec(mf.stdout, c, label, molabel, start=1, **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
Ejemplo n.º 9
0
Archivo: boys.py Proyecto: sunqm/pyscf
def atomic_init_guess(mol, mo_coeff):
    s = mol.intor_symmetric('int1e_ovlp')
    c = orth.orth_ao(mol, s=s)
    mo = reduce(numpy.dot, (c.conj().T, s, mo_coeff))
# Find the AOs which have largest overlap to MOs
    idx = numpy.argsort(numpy.einsum('pi,pi->p', mo.conj(), mo))
    nmo = mo.shape[1]
    idx = sorted(idx[-nmo:])

    # Rotate mo_coeff, make it as close as possible to AOs
    u, w, vh = numpy.linalg.svd(mo[idx])
    return lib.dot(u, vh).conj().T
Ejemplo n.º 10
0
Archivo: uhf.py Proyecto: sunqm/pyscf
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis; Dipole moment
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    nmo = len(mo_occ[0])
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        log.note('**** MO energy ****')
        log.note('                             alpha | beta                alpha | beta')
        for i in range(nmo):
            log.note('MO #%-3d energy= %-18.15g | %-18.15g occ= %g | %g',
                     i+MO_BASE, mo_energy[0][i], mo_energy[1][i],
                     mo_occ[0][i], mo_occ[1][i])

    ovlp_ao = mf.get_ovlp()
    if log.verbose >= logger.DEBUG:
        label = mf.mol.ao_labels()
        if with_meta_lowdin:
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) for alpha spin **')
            orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
            c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
            dump_mat.dump_rec(mf.stdout, c_inv.dot(mo_coeff[0]), label,
                              start=MO_BASE, **kwargs)
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) for beta spin **')
            dump_mat.dump_rec(mf.stdout, c_inv.dot(mo_coeff[1]), label,
                              start=MO_BASE, **kwargs)
        else:
            log.debug(' ** MO coefficients (expansion on AOs) for alpha spin **')
            dump_mat.dump_rec(mf.stdout, mo_coeff[0], label,
                              start=MO_BASE, **kwargs)
            log.debug(' ** MO coefficients (expansion on AOs) for beta spin **')
            dump_mat.dump_rec(mf.stdout, mo_coeff[1], label,
                              start=MO_BASE, **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        return (mf.mulliken_meta(mf.mol, dm, s=ovlp_ao, verbose=log),
                mf.dip_moment(mf.mol, dm, verbose=log))
    else:
        return (mf.mulliken_pop(mf.mol, dm, s=ovlp_ao, verbose=log),
                mf.dip_moment(mf.mol, dm, verbose=log))
Ejemplo n.º 11
0
Archivo: uhf.py Proyecto: sunqm/pyscf
def mulliken_meta(mol, dm_ao, verbose=logger.DEBUG,
                  pre_orth_method=PRE_ORTH_METHOD, s=None):
    '''Mulliken population analysis, based on meta-Lowdin AOs.
    '''
    from pyscf.lo import orth
    if s is None: s = hf.get_ovlp(mol)
    log = logger.new_logger(mol, verbose)
    if isinstance(dm_ao, numpy.ndarray) and dm_ao.ndim == 2:
        dm_ao = numpy.array((dm_ao*.5, dm_ao*.5))
    c = orth.restore_ao_character(mol, pre_orth_method)
    orth_coeff = orth.orth_ao(mol, 'meta_lowdin', pre_orth_ao=c, s=s)
    c_inv = numpy.dot(orth_coeff.T, s)
    dm_a = reduce(numpy.dot, (c_inv, dm_ao[0], c_inv.T.conj()))
    dm_b = reduce(numpy.dot, (c_inv, dm_ao[1], c_inv.T.conj()))

    log.note(' ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **')
    return mulliken_pop(mol, (dm_a,dm_b), numpy.eye(orth_coeff.shape[0]), log)
Ejemplo n.º 12
0
def mulliken_pop_meta_lowdin_ao(mol, dm_ao, verbose=logger.DEBUG,
                                pre_orth_method='ANO'):
    '''Mulliken population analysis, based on meta-Lowdin AOs.
    '''
    from pyscf.lo import orth
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mol.stdout, verbose)
    c = orth.pre_orth_ao(mol, pre_orth_method)
    orth_coeff = orth.orth_ao(mol, 'meta_lowdin', pre_orth_ao=c)
    c_inv = numpy.linalg.inv(orth_coeff)
    dm_a = reduce(numpy.dot, (c_inv, dm_ao[0], c_inv.T.conj()))
    dm_b = reduce(numpy.dot, (c_inv, dm_ao[1], c_inv.T.conj()))

    log.info(' ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **')
    return mulliken_pop(mol, (dm_a,dm_b), numpy.eye(orth_coeff.shape[0]), log)
Ejemplo n.º 13
0
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        log.note('**** MO energy ****')
        if getattr(mo_energy, 'mo_ea', None) is not None:
            mo_ea = mo_energy.mo_ea
            mo_eb = mo_energy.mo_eb
            log.note('                Roothaan           | alpha              | beta')
            for i,c in enumerate(mo_occ):
                log.note('MO #%-3d energy= %-18.15g | %-18.15g | %-18.15g occ= %g',
                         i+MO_BASE, mo_energy[i], mo_ea[i], mo_eb[i], c)
        else:
            for i,c in enumerate(mo_occ):
                log.note('MO #%-3d energy= %-18.15g occ= %g',
                         i+MO_BASE, mo_energy[i], c)

    ovlp_ao = mf.get_ovlp()
    if log.verbose >= logger.DEBUG:
        label = mf.mol.ao_labels()
        if with_meta_lowdin:
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
            c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
        else:
            log.debug(' ** MO coefficients (expansion on AOs) **')
            c = mo_coeff
        dump_mat.dump_rec(mf.stdout, c, label, start=MO_BASE, **kwargs)
    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        pop_and_charge = mf.mulliken_meta(mf.mol, dm, s=ovlp_ao, verbose=log)
    else:
        pop_and_charge = mf.mulliken_pop(mf.mol, dm, s=ovlp_ao, verbose=log)
    dip = mf.dip_moment(mf.mol, dm, verbose=log)
    return pop_and_charge, dip
Ejemplo n.º 14
0
def mulliken_meta(mol, dm, verbose=logger.DEBUG, pre_orth_method='ANO',
                  s=None):
    '''Mulliken population analysis, based on meta-Lowdin AOs.
    In the meta-lowdin, the AOs are grouped in three sets: core, valence and
    Rydberg, the orthogonalization are carreid out within each subsets.

    Args:
        mol : an instance of :class:`Mole`

        dm : ndarray or 2-item list of ndarray
            Density matrix.  ROHF dm is a 2-item list of 2D array

    Kwargs:
        verbose : int or instance of :class:`lib.logger.Logger`

        pre_orth_method : str
            Pre-orthogonalization, which localized GTOs for each atom.
            To obtain the occupied and unoccupied atomic shells, there are
            three methods

            | 'ano'   : Project GTOs to ANO basis
            | 'minao' : Project GTOs to MINAO basis
            | 'scf'   : Fraction-averaged RHF

    '''
    from pyscf.lo import orth
    if s is None:
        s = get_ovlp(mol)
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mol.stdout, verbose)
    c = orth.pre_orth_ao(mol, pre_orth_method)
    orth_coeff = orth.orth_ao(mol, 'meta_lowdin', pre_orth_ao=c, s=s)
    c_inv = numpy.dot(orth_coeff.T, s)
    if isinstance(dm, numpy.ndarray) and dm.ndim == 2:
        dm = reduce(numpy.dot, (c_inv, dm, c_inv.T.conj()))
    else:  # ROHF
        dm = reduce(numpy.dot, (c_inv, dm[0]+dm[1], c_inv.T.conj()))

    log.info(' ** Mulliken pop on meta-lowdin orthogonal AOs  **')
    return mulliken_pop(mol, dm, numpy.eye(orth_coeff.shape[0]), log)
Ejemplo n.º 15
0
def atomic_pops(mol, mo_coeff, method='meta_lowdin'):
    '''kwarg method can be one of mulliken, lowdin, meta_lowdin
    '''
    s = mol.intor_symmetric('cint1e_ovlp_sph')
    nmo = mo_coeff.shape[1]
    proj = numpy.empty((mol.natm,nmo,nmo))

    if method.lower() == 'mulliken':
        for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()):
            csc = reduce(numpy.dot, (mo_coeff[p0:p1].T, s[p0:p1], mo_coeff))
            proj[i] = (csc + csc.T) * .5

    elif method.lower() in ('lowdin', 'meta_lowdin'):
        csc = reduce(numpy.dot, (mo_coeff.T, s, orth.orth_ao(mol, method, s=s)))
        for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()):
            proj[i] = numpy.dot(csc[:,p0:p1], csc[:,p0:p1].T)
    else:
        raise KeyError('method = %s' % method)

    return proj
Ejemplo n.º 16
0
Archivo: uhf.py Proyecto: matk86/pyscf
def mulliken_meta(mol, dm_ao, verbose=logger.DEBUG, pre_orth_method="ANO", s=None):
    """Mulliken population analysis, based on meta-Lowdin AOs.
    """
    from pyscf.lo import orth

    if s is None:
        s = hf.get_ovlp(mol)
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mol.stdout, verbose)
    if isinstance(dm_ao, numpy.ndarray) and dm_ao.ndim == 2:
        dm_ao = numpy.array((dm_ao * 0.5, dm_ao * 0.5))
    c = orth.pre_orth_ao(mol, pre_orth_method)
    orth_coeff = orth.orth_ao(mol, "meta_lowdin", pre_orth_ao=c, s=s)
    c_inv = numpy.dot(orth_coeff.T, s)
    dm_a = reduce(numpy.dot, (c_inv, dm_ao[0], c_inv.T.conj()))
    dm_b = reduce(numpy.dot, (c_inv, dm_ao[1], c_inv.T.conj()))

    log.info(" ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **")
    return mulliken_pop(mol, (dm_a, dm_b), numpy.eye(orth_coeff.shape[0]), log)
Ejemplo n.º 17
0
Archivo: uhf.py Proyecto: eronca/pyscf
def analyze(mf, verbose=logger.DEBUG, **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis; Dipole moment
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, verbose)
    ss, s = mf.spin_square((mo_coeff[0][:,mo_occ[0]>0],
                            mo_coeff[1][:,mo_occ[1]>0]), mf.get_ovlp())
    log.note('multiplicity <S^2> = %.8g  2S+1 = %.8g', ss, s)

    log.note('**** MO energy ****')
    log.note('                             alpha | beta                alpha | beta')
    for i in range(mo_occ.shape[1]):
        log.note('MO #%-3d energy= %-18.15g | %-18.15g occ= %g | %g',
                 i+1, mo_energy[0][i], mo_energy[1][i],
                 mo_occ[0][i], mo_occ[1][i])
    ovlp_ao = mf.get_ovlp()
    if verbose >= logger.DEBUG:
        log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) for alpha spin **')
        label = mf.mol.spheric_labels(True)
        orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
        c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
        dump_mat.dump_rec(mf.stdout, c_inv.dot(mo_coeff[0]), label, start=1,
                          **kwargs)
        log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) for beta spin **')
        dump_mat.dump_rec(mf.stdout, c_inv.dot(mo_coeff[1]), label, start=1,
                          **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return (mf.mulliken_meta(mf.mol, dm, s=ovlp_ao, verbose=log),
            mf.dip_moment(mf.mol, dm, verbose=log))
Ejemplo n.º 18
0
    def analyze(self, mo_coeff=None, ci=None, verbose=None,
                large_ci_tol=LARGE_CI_TOL, with_meta_lowdin=WITH_META_LOWDIN,
                **kwargs):
        from pyscf.lo import orth
        from pyscf.tools import dump_mat
        if mo_coeff is None: mo_coeff = self.mo_coeff
        if ci is None: ci = self.ci
        log = logger.new_logger(self, verbose)
        nelecas = self.nelecas
        ncas = self.ncas
        ncore = self.ncore
        mocore_a = mo_coeff[0][:,:ncore[0]]
        mocas_a = mo_coeff[0][:,ncore[0]:ncore[0]+ncas]
        mocore_b = mo_coeff[1][:,:ncore[1]]
        mocas_b = mo_coeff[1][:,ncore[1]:ncore[1]+ncas]

        label = self.mol.ao_labels()
        if (isinstance(ci, (list, tuple)) and
            not isinstance(self.fcisolver, addons.StateAverageFCISolver)):
            log.warn('Mulitple states found in UCASCI solver. Density '
                     'matrix of first state is generated in .analyze() function.')
            civec = ci[0]
        else:
            civec = ci
        casdm1a, casdm1b = self.fcisolver.make_rdm1s(civec, ncas, nelecas)
        dm1a = numpy.dot(mocore_a, mocore_a.T)
        dm1a += reduce(numpy.dot, (mocas_a, casdm1a, mocas_a.T))
        dm1b = numpy.dot(mocore_b, mocore_b.T)
        dm1b += reduce(numpy.dot, (mocas_b, casdm1b, mocas_b.T))
        if log.verbose >= logger.DEBUG2:
            log.debug2('alpha density matrix (on AO)')
            dump_mat.dump_tri(self.stdout, dm1a, label)
            log.debug2('beta density matrix (on AO)')
            dump_mat.dump_tri(self.stdout, dm1b, label)

        if log.verbose >= logger.INFO:
            ovlp_ao = self._scf.get_ovlp()
            occa, ucasa = self._eig(-casdm1a, ncore[0], ncore[0]+ncas)
            occb, ucasb = self._eig(-casdm1b, ncore[1], ncore[1]+ncas)
            log.info('Natural alpha-occupancy %s', str(-occa))
            log.info('Natural beta-occupancy %s', str(-occb))
            mocas_a = numpy.dot(mocas_a, ucasa)
            mocas_b = numpy.dot(mocas_b, ucasb)
            if with_meta_lowdin:
                orth_coeff = orth.orth_ao(self.mol, 'meta_lowdin', s=ovlp_ao)
                mocas_a = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas_a))
                mocas_b = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas_b))
                log.info('Natural alpha-orbital (expansion on meta-Lowdin AOs) in CAS space')
                dump_mat.dump_rec(log.stdout, mocas_a, label, start=1, **kwargs)
                log.info('Natural beta-orbital (expansion on meta-Lowdin AOs) in CAS space')
                dump_mat.dump_rec(log.stdout, mocas_b, label, start=1, **kwargs)
            else:
                log.info('Natural alpha-orbital (expansion on AOs) in CAS space')
                dump_mat.dump_rec(log.stdout, mocas_a, label, start=1, **kwargs)
                log.info('Natural beta-orbital (expansion on AOs) in CAS space')
                dump_mat.dump_rec(log.stdout, mocas_b, label, start=1, **kwargs)

            tol = getattr(__config__, 'mcscf_addons_map2hf_tol', 0.4)
            s = reduce(numpy.dot, (mo_coeff[0].T, ovlp_ao, self._scf.mo_coeff[0]))
            idx = numpy.argwhere(abs(s)>tol)
            for i,j in idx:
                log.info('alpha <mo-mcscf|mo-hf> %d  %d  %12.8f' % (i+1,j+1,s[i,j]))
            s = reduce(numpy.dot, (mo_coeff[1].T, ovlp_ao, self._scf.mo_coeff[1]))
            idx = numpy.argwhere(abs(s)>tol)
            for i,j in idx:
                log.info('beta <mo-mcscf|mo-hf> %d  %d  %12.8f' % (i+1,j+1,s[i,j]))

            if getattr(self.fcisolver, 'large_ci', None) and ci is not None:
                log.info('\n** Largest CI components **')
                if isinstance(ci, (tuple, list)):
                    for i, state in enumerate(ci):
                        log.info('  [alpha occ-orbitals] [beta occ-orbitals]  state %-3d CI coefficient', i)
                        res = self.fcisolver.large_ci(state, self.ncas, self.nelecas,
                                                      large_ci_tol, return_strs=False)
                        for c,ia,ib in res:
                            log.info('  %-20s %-30s %.12f', ia, ib, c)
                else:
                    log.info('  [alpha occ-orbitals] [beta occ-orbitals]            CI coefficient')
                    res = self.fcisolver.large_ci(ci, self.ncas, self.nelecas,
                                                  large_ci_tol, return_strs=False)
                    for c,ia,ib in res:
                        log.info('  %-20s %-30s %.12f', ia, ib, c)
        return dm1a, dm1b
Ejemplo n.º 19
0
def cas_natorb(mc, mo_coeff=None, ci=None, eris=None, sort=False,
               casdm1=None, verbose=None, with_meta_lowdin=WITH_META_LOWDIN):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn
    accordingly

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    log = logger.new_logger(mc, verbose)
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    # orbital symmetry is reserved in this _eig call
    occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        casorb_idx = numpy.argsort(occ.round(9), kind='mergesort')
        occ = occ[casorb_idx]
        ucas = ucas[:,casorb_idx]

    occ = -occ
    mo_occ = numpy.zeros(mo_coeff.shape[1])
    mo_occ[:ncore] = 2
    mo_occ[ncore:nocc] = occ

    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:,ncore:nocc] = numpy.dot(mo_coeff[:,ncore:nocc], ucas)
    if getattr(mo_coeff, 'orbsym', None) is not None:
        orbsym = numpy.copy(mo_coeff.orbsym)
        if sort:
            orbsym[ncore:nocc] = orbsym[ncore:nocc][casorb_idx]
        mo_coeff1 = lib.tag_array(mo_coeff1, orbsym=orbsym)

    fcivec = None
    if getattr(mc.fcisolver, 'transform_ci_for_orbital_rotation', None):
        if isinstance(ci, numpy.ndarray):
            fcivec = mc.fcisolver.transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)
        elif (isinstance(ci, (list, tuple)) and
              all(isinstance(x[0], numpy.ndarray) for x in ci)):
            fcivec = [mc.fcisolver.transform_ci_for_orbital_rotation(x, ncas, nelecas, ucas)
                      for x in ci]
    elif getattr(mc.fcisolver, 'states_transform_ci_for_orbital_rotation', None):
        fcivec = mc.fcisolver.states_transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)

    if fcivec is None:
        log.info('FCI vector not available, call CASCI to update wavefunction')
        mocas = mo_coeff1[:,ncore:nocc]
        hcore = mc.get_hcore()
        dm_core = numpy.dot(mo_coeff1[:,:ncore]*2, mo_coeff1[:,:ncore].T)
        ecore = mc.energy_nuc()
        ecore+= numpy.einsum('ij,ji', hcore, dm_core)
        h1eff = reduce(numpy.dot, (mocas.T, hcore, mocas))
        if getattr(eris, 'ppaa', None) is not None:
            ecore += eris.vhf_c[:ncore,:ncore].trace()
            h1eff += reduce(numpy.dot, (ucas.T, eris.vhf_c[ncore:nocc,ncore:nocc], ucas))
            aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc,ncore:nocc,:,:], ncas)
            aaaa = ao2mo.incore.full(aaaa, ucas)
        else:
            if getattr(mc, 'with_df', None):
                raise NotImplementedError('cas_natorb for DFCASCI/DFCASSCF')
            corevhf = mc.get_veff(mc.mol, dm_core)
            ecore += numpy.einsum('ij,ji', dm_core, corevhf) * .5
            h1eff += reduce(numpy.dot, (mocas.T, corevhf, mocas))
            aaaa = ao2mo.kernel(mc.mol, mocas)

        # See label_symmetry_ function in casci_symm.py which initialize the
        # orbital symmetry information in fcisolver.  This orbital symmetry
        # labels should be reordered to match the sorted active space orbitals.
        if sort and getattr(mo_coeff1, 'orbsym', None) is not None:
            mc.fcisolver.orbsym = mo_coeff1.orbsym[ncore:nocc]

        max_memory = max(400, mc.max_memory-lib.current_memory()[0])
        e, fcivec = mc.fcisolver.kernel(h1eff, aaaa, ncas, nelecas, ecore=ecore,
                                        max_memory=max_memory, verbose=log)
        log.debug('In Natural orbital, CASCI energy = %s', e)

    if log.verbose >= logger.INFO:
        ovlp_ao = mc._scf.get_ovlp()
        # where_natorb gives the new locations of the natural orbitals
        where_natorb = mo_1to1map(ucas)
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(occ))
        if with_meta_lowdin:
            log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
            label = mc.mol.ao_labels()
            orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
            mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff1[:,ncore:nocc]))
        else:
            log.info('Natural orbital (expansion on AOs) in CAS space')
            label = mc.mol.ao_labels()
            mo_cas = mo_coeff1[:,ncore:nocc]
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:,ncore:nocc].T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f',
                         ncore+i+1, j+1, s[i,j])
    return mo_coeff1, fcivec, mo_occ
Ejemplo n.º 20
0
def cas_natorb(mc, mo_coeff=None, ci=None, eris=None, sort=False,
               casdm1=None, verbose=None, with_meta_lowdin=WITH_META_LOWDIN):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    log = logger.new_logger(mc, verbose)
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    # orbital symmetry is reserved in this _eig call
    occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        casorb_idx = numpy.argsort(occ.round(9), kind='mergesort')
        occ = occ[casorb_idx]
        ucas = ucas[:,casorb_idx]

    occ = -occ
    mo_occ = numpy.zeros(mo_coeff.shape[1])
    mo_occ[:ncore] = 2
    mo_occ[ncore:nocc] = occ

    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:,ncore:nocc] = numpy.dot(mo_coeff[:,ncore:nocc], ucas)
    if getattr(mo_coeff, 'orbsym', None) is not None:
        orbsym = numpy.copy(mo_coeff.orbsym)
        if sort:
            orbsym[ncore:nocc] = orbsym[ncore:nocc][casorb_idx]
        mo_coeff1 = lib.tag_array(mo_coeff1, orbsym=orbsym)

    if isinstance(ci, numpy.ndarray):
        fcivec = fci.addons.transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)
    elif isinstance(ci, (tuple, list)) and isinstance(ci[0], numpy.ndarray):
        # for state-average eigenfunctions
        fcivec = [fci.addons.transform_ci_for_orbital_rotation(x, ncas, nelecas, ucas)
                  for x in ci]
    else:
        log.info('FCI vector not available, call CASCI for wavefunction')
        mocas = mo_coeff1[:,ncore:nocc]
        hcore = mc.get_hcore()
        dm_core = numpy.dot(mo_coeff1[:,:ncore]*2, mo_coeff1[:,:ncore].T)
        ecore = mc.energy_nuc()
        ecore+= numpy.einsum('ij,ji', hcore, dm_core)
        h1eff = reduce(numpy.dot, (mocas.T, hcore, mocas))
        if getattr(eris, 'ppaa', None) is not None:
            ecore += eris.vhf_c[:ncore,:ncore].trace()
            h1eff += reduce(numpy.dot, (ucas.T, eris.vhf_c[ncore:nocc,ncore:nocc], ucas))
            aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc,ncore:nocc,:,:], ncas)
            aaaa = ao2mo.incore.full(aaaa, ucas)
        else:
            if getattr(mc, 'with_df', None):
                raise NotImplementedError('cas_natorb for DFCASCI/DFCASSCF')
            corevhf = mc.get_veff(mc.mol, dm_core)
            ecore += numpy.einsum('ij,ji', dm_core, corevhf) * .5
            h1eff += reduce(numpy.dot, (mocas.T, corevhf, mocas))
            aaaa = ao2mo.kernel(mc.mol, mocas)

        # See label_symmetry_ function in casci_symm.py which initialize the
        # orbital symmetry information in fcisolver.  This orbital symmetry
        # labels should be reordered to match the sorted active space orbitals.
        if sort and getattr(mo_coeff1, 'orbsym', None) is not None:
            mc.fcisolver.orbsym = mo_coeff1.orbsym[ncore:nocc]

        max_memory = max(400, mc.max_memory-lib.current_memory()[0])
        e, fcivec = mc.fcisolver.kernel(h1eff, aaaa, ncas, nelecas, ecore=ecore,
                                        max_memory=max_memory, verbose=log)
        log.debug('In Natural orbital, CASCI energy = %s', e)

    if log.verbose >= logger.INFO:
        ovlp_ao = mc._scf.get_ovlp()
        # where_natorb gives the new locations of the natural orbitals
        where_natorb = mo_1to1map(ucas)
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(occ))
        if with_meta_lowdin:
            log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
            label = mc.mol.ao_labels()
            orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
            mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff1[:,ncore:nocc]))
        else:
            log.info('Natural orbital (expansion on AOs) in CAS space')
            label = mc.mol.ao_labels()
            mo_cas = mo_coeff1[:,ncore:nocc]
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:,ncore:nocc].T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f',
                         ncore+i+1, j+1, s[i,j])
    return mo_coeff1, fcivec, mo_occ
Ejemplo n.º 21
0
    def analyze(self,
                mo_coeff=None,
                ci=None,
                verbose=None,
                large_ci_tol=LARGE_CI_TOL,
                with_meta_lowdin=WITH_META_LOWDIN,
                **kwargs):
        from pyscf.lo import orth
        from pyscf.tools import dump_mat
        if mo_coeff is None: mo_coeff = self.mo_coeff
        if ci is None: ci = self.ci
        log = logger.new_logger(self, verbose)
        nelecas = self.nelecas
        ncas = self.ncas
        ncore = self.ncore
        mocore_a = mo_coeff[0][:, :ncore[0]]
        mocas_a = mo_coeff[0][:, ncore[0]:ncore[0] + ncas]
        mocore_b = mo_coeff[1][:, :ncore[1]]
        mocas_b = mo_coeff[1][:, ncore[1]:ncore[1] + ncas]

        label = self.mol.ao_labels()
        if (isinstance(ci, (list, tuple)) and
                not isinstance(self.fcisolver, addons.StateAverageFCISolver)):
            log.warn(
                'Mulitple states found in UCASCI solver. Density '
                'matrix of first state is generated in .analyze() function.')
            civec = ci[0]
        else:
            civec = ci
        casdm1a, casdm1b = self.fcisolver.make_rdm1s(civec, ncas, nelecas)
        dm1a = numpy.dot(mocore_a, mocore_a.T)
        dm1a += reduce(numpy.dot, (mocas_a, casdm1a, mocas_a.T))
        dm1b = numpy.dot(mocore_b, mocore_b.T)
        dm1b += reduce(numpy.dot, (mocas_b, casdm1b, mocas_b.T))
        if log.verbose >= logger.DEBUG2:
            log.debug2('alpha density matrix (on AO)')
            dump_mat.dump_tri(self.stdout, dm1a, label)
            log.debug2('beta density matrix (on AO)')
            dump_mat.dump_tri(self.stdout, dm1b, label)

        if log.verbose >= logger.INFO:
            ovlp_ao = self._scf.get_ovlp()
            occa, ucasa = self._eig(-casdm1a, ncore[0], ncore[0] + ncas)
            occb, ucasb = self._eig(-casdm1b, ncore[1], ncore[1] + ncas)
            log.info('Natural alpha-occupancy %s', str(-occa))
            log.info('Natural beta-occupancy %s', str(-occb))
            mocas_a = numpy.dot(mocas_a, ucasa)
            mocas_b = numpy.dot(mocas_b, ucasb)
            if with_meta_lowdin:
                orth_coeff = orth.orth_ao(self.mol, 'meta_lowdin', s=ovlp_ao)
                mocas_a = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas_a))
                mocas_b = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas_b))
                log.info(
                    'Natural alpha-orbital (expansion on meta-Lowdin AOs) in CAS space'
                )
                dump_mat.dump_rec(log.stdout,
                                  mocas_a,
                                  label,
                                  start=1,
                                  **kwargs)
                log.info(
                    'Natural beta-orbital (expansion on meta-Lowdin AOs) in CAS space'
                )
                dump_mat.dump_rec(log.stdout,
                                  mocas_b,
                                  label,
                                  start=1,
                                  **kwargs)
            else:
                log.info(
                    'Natural alpha-orbital (expansion on AOs) in CAS space')
                dump_mat.dump_rec(log.stdout,
                                  mocas_a,
                                  label,
                                  start=1,
                                  **kwargs)
                log.info(
                    'Natural beta-orbital (expansion on AOs) in CAS space')
                dump_mat.dump_rec(log.stdout,
                                  mocas_b,
                                  label,
                                  start=1,
                                  **kwargs)

            tol = getattr(__config__, 'mcscf_addons_map2hf_tol', 0.4)
            s = reduce(numpy.dot,
                       (mo_coeff[0].T, ovlp_ao, self._scf.mo_coeff[0]))
            idx = numpy.argwhere(abs(s) > tol)
            for i, j in idx:
                log.info('alpha <mo-mcscf|mo-hf> %d  %d  %12.8f' %
                         (i + 1, j + 1, s[i, j]))
            s = reduce(numpy.dot,
                       (mo_coeff[1].T, ovlp_ao, self._scf.mo_coeff[1]))
            idx = numpy.argwhere(abs(s) > tol)
            for i, j in idx:
                log.info('beta <mo-mcscf|mo-hf> %d  %d  %12.8f' %
                         (i + 1, j + 1, s[i, j]))

            if hasattr(self.fcisolver, 'large_ci') and ci is not None:
                log.info('\n** Largest CI components **')
                if isinstance(ci, (tuple, list)):
                    for i, state in enumerate(ci):
                        log.info(
                            '  [alpha occ-orbitals] [beta occ-orbitals]  state %-3d CI coefficient',
                            i)
                        res = self.fcisolver.large_ci(state,
                                                      self.ncas,
                                                      self.nelecas,
                                                      large_ci_tol,
                                                      return_strs=False)
                        for c, ia, ib in res:
                            log.info('  %-20s %-30s %.12f', ia, ib, c)
                else:
                    log.info(
                        '  [alpha occ-orbitals] [beta occ-orbitals]            CI coefficient'
                    )
                    res = self.fcisolver.large_ci(ci,
                                                  self.ncas,
                                                  self.nelecas,
                                                  large_ci_tol,
                                                  return_strs=False)
                    for c, ia, ib in res:
                        log.info('  %-20s %-30s %.12f', ia, ib, c)
        return dm1a, dm1b
Ejemplo n.º 22
0
def cas_natorb(mc, mo_coeff=None, ci=None, eris=None, sort=False,
               casdm1=None, verbose=None):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.  Be careful with this
            option since the resultant natural orbitals might have the
            different symmetry to the irreps indicated by CASSCF.orbsym

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mc.stdout, mc.verbose)
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    # orbital symmetry is reserved in this _eig call
    occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        idx = numpy.argsort(occ)
        occ = occ[idx]
        ucas = ucas[:,idx]
# restore phase
# where_natorb gives the location of the natural orbital for the input cas
# orbitals.  gen_strings4orblist map thes sorted strings (on CAS orbital) to
# the unsorted determinant strings (on natural orbital). e.g.  (3o,2e) system
#       CAS orbital      1  2  3
#       natural orbital  3  1  2        <= by mo_1to1map
#       CASorb-strings   0b011, 0b101, 0b110
#                    ==  (1,2), (1,3), (2,3)
#       natorb-strings   (3,1), (3,2), (1,2)
#                    ==  0B101, 0B110, 0B011    <= by gen_strings4orblist
# then argsort to translate the string representation to the address
#       [2(=0B011), 0(=0B101), 1(=0B110)]
# to indicate which CASorb-strings address to be loaded in each natorb-strings slot
    where_natorb = mo_1to1map(ucas)
    for i, k in enumerate(where_natorb):
        if ucas[i,k] < 0:
            ucas[:,k] *= -1

    occ = -occ
    mo_occ = numpy.zeros(mo_coeff.shape[1])
    mo_occ[:ncore] = 2
    mo_occ[ncore:nocc] = occ

    if isinstance(ci, numpy.ndarray):
        fcivec = fci.addons.transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)
    elif isinstance(ci, (tuple, list)) and isinstance(ci[0], numpy.ndarray):
        # for state-average eigenfunctions
        fcivec = [fci.addons.transform_ci_for_orbital_rotation(x, ncas, nelecas, ucas)
                  for x in ci]
    else:
        log.info('FCI vector not available, call CASCI for wavefunction')
        mocas = mo_coeff1[:,ncore:nocc]
        h1eff = reduce(numpy.dot, (mocas.T, mc.get_hcore(), mocas))
        if eris is not None and hasattr(eris, 'ppaa'):
            h1eff += reduce(numpy.dot, (ucas.T, eris.vhf_c[ncore:nocc,ncore:nocc], ucas))
            aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc,ncore:nocc,:,:], ncas)
            aaaa = ao2mo.incore.full(aaaa, ucas)
        else:
            dm_core = numpy.dot(mo_coeff[:,:ncore]*2, mo_coeff[:,:ncore].T)
            vj, vk = mc._scf.get_jk(mc.mol, dm_core)
            h1eff += reduce(numpy.dot, (mocas.T, vj-vk*.5, mocas))
            aaaa = ao2mo.kernel(mc.mol, mocas)
        max_memory = max(400, mc.max_memory-lib.current_memory()[0])
        e_cas, fcivec = mc.fcisolver.kernel(h1eff, aaaa, ncas, nelecas,
                                            max_memory=max_memory, verbose=log)
        log.debug('In Natural orbital, CI energy = %.12g', e_cas)

    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:,ncore:nocc] = numpy.dot(mo_coeff[:,ncore:nocc], ucas)
    if log.verbose >= logger.INFO:
        ovlp_ao = mc._scf.get_ovlp()
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(occ))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        label = mc.mol.spheric_labels(True)
        orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff1[:,ncore:nocc]))
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:,ncore:nocc].T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f',
                         ncore+i+1, j+1, s[i,j])
    return mo_coeff1, fcivec, mo_occ
Ejemplo n.º 23
0
    def analyze(self, verbose=None, **kwargs):
        if verbose is None: verbose = self.verbose
        from pyscf.lo import orth
        from pyscf.tools import dump_mat
        if not self.mol.symmetry:
            return rohf.ROHF.analyze(self, verbose, **kwargs)

        mo_energy = self.mo_energy
        mo_occ = self.mo_occ
        mo_coeff = self.mo_coeff
        log = logger.Logger(self.stdout, verbose)
        mol = self.mol
        nirrep = len(mol.irrep_id)
        ovlp_ao = self.get_ovlp()

        orbsym = get_orbsym(self.mol, mo_coeff)
        wfnsym = 0
        ndoccs = []
        nsoccs = []
        for k,ir in enumerate(mol.irrep_id):
            ndoccs.append(sum(orbsym[mo_occ==2] == ir))
            nsoccs.append(sum(orbsym[mo_occ==1] == ir))
            if nsoccs[k] % 2:
                wfnsym ^= ir
        if mol.groupname in ('Dooh', 'Coov'):
            log.info('TODO: total symmetry for %s', mol.groupname)
        else:
            log.info('total symmetry = %s',
                     symm.irrep_id2name(mol.groupname, wfnsym))
        log.info('occupancy for each irrep:  ' + (' %4s'*nirrep),
                 *mol.irrep_name)
        log.info('double occ                 ' + (' %4d'*nirrep), *ndoccs)
        log.info('single occ                 ' + (' %4d'*nirrep), *nsoccs)
        log.info('**** MO energy ****')
        irname_full = {}
        for k,ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        if self._focka_ao is None:
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g',
                         k+1, irname_full[j], irorbcnt[j],
                         mo_energy[k], mo_occ[k])
        else:
            mo_ea = numpy.einsum('ik,ik->k', mo_coeff, self._focka_ao.dot(mo_coeff))
            mo_eb = numpy.einsum('ik,ik->k', mo_coeff, self._fockb_ao.dot(mo_coeff))
            log.note('                          Roothaan           | alpha              | beta')
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                log.note('MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g',
                         k+1, irname_full[j], irorbcnt[j],
                         mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k])

        if verbose >= logger.DEBUG:
            label = mol.ao_labels()
            molabel = []
            irorbcnt = {}
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
            c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
            dump_mat.dump_rec(self.stdout, c, label, molabel, start=1, **kwargs)

        dm = self.make_rdm1(mo_coeff, mo_occ)
        return self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=verbose)
Ejemplo n.º 24
0
    def __init__(self,
                 the_mf,
                 active_orbs,
                 localizationtype,
                 ao_rotation=None,
                 use_full_hessian=True,
                 localization_threshold=1e-6):

        assert ((localizationtype == 'meta_lowdin')
                or (localizationtype == 'boys')
                or (localizationtype == 'lowdin')
                or (localizationtype == 'iao'))
        self.num_mf_stab_checks = 0

        # Information on the full HF problem
        self.mol = the_mf.mol
        self._scf = the_mf
        self.max_memory = the_mf.max_memory
        self.get_jk_ao = partial(the_mf.get_jk, self.mol)
        self.get_veff_ao = partial(the_mf.get_veff, self.mol)
        self.get_k_ao = partial(the_mf.get_k, self.mol)
        self.fullovlpao = the_mf.get_ovlp
        self.fullEhf = the_mf.e_tot
        self.fullRDM_ao = np.asarray(the_mf.make_rdm1())
        if self.fullRDM_ao.ndim == 3:
            self.fullSDM_ao = self.fullRDM_ao[0] - self.fullRDM_ao[1]
            self.fullRDM_ao = self.fullRDM_ao[0] + self.fullRDM_ao[1]
        else:
            self.fullSDM_ao = np.zeros_like(self.fullRDM_ao)
        self.fullJK_ao = self.get_veff_ao(
            dm=self.fullRDM_ao, dm_last=0, vhf_last=0,
            hermi=1)  #Last 3 numbers: dm_last, vhf_last, hermi
        if self.fullJK_ao.ndim == 3:
            self.fullJK_ao = self.fullJK_ao[0]
            # Because I gave it a spin-summed 1-RDM, the two spins for JK will necessarily be identical
        self.fullFOCK_ao = the_mf.get_hcore() + self.fullJK_ao
        self.e_tot = the_mf.e_tot
        self.x2c = isinstance(the_mf, x2c._X2C_SCF)

        # Active space information
        self._which = localizationtype
        self.active = np.zeros([self.mol.nao_nr()], dtype=int)
        self.active[active_orbs] = 1
        self.norbs_tot = np.sum(self.active)  # Number of active space orbitals
        self.nelec_tot = int(
            np.rint(self.mol.nelectron -
                    np.sum(the_mf.mo_occ[self.active == 0]))
        )  # Total number of electrons minus frozen part

        # Localize the orbitals
        if ((self._which == 'meta_lowdin') or (self._which == 'boys')):
            if (self._which == 'meta_lowdin'):
                assert (self.norbs_tot == self.mol.nao_nr()
                        )  # Full active space required
            if (self._which == 'boys'):
                self.ao2loc = the_mf.mo_coeff[:, self.active == 1]
            if (self.norbs_tot == self.mol.nao_nr()
                ):  # If you want the full active, do meta-Lowdin
                nao.AOSHELL[4] = ['1s0p0d0f', '2s1p0d0f'
                                  ]  # redefine the valence shell for Be
                self.ao2loc = orth.orth_ao(self.mol, 'meta_lowdin')
                if (ao_rotation != None):
                    self.ao2loc = np.dot(self.ao2loc, ao_rotation.T)
            if (self._which == 'boys'):
                old_verbose = self.mol.verbose
                self.mol.verbose = 5
                loc = boys.Boys(self.mol, self.ao2loc)
                #                loc = localizer.localizer( self.mol, self.ao2loc, self._which, use_full_hessian )
                self.mol.verbose = old_verbose
                #                self.ao2loc = loc.optimize( threshold=localization_threshold )
                self.ao2loc = loc.kernel()
            self.TI_OK = False  # Check yourself if OK, then overwrite
        if (self._which == 'lowdin'):
            assert (self.norbs_tot == self.mol.nao_nr()
                    )  # Full active space required
            ovlp = self.mol.intor('cint1e_ovlp_sph')
            ovlp_eigs, ovlp_vecs = np.linalg.eigh(ovlp)
            assert (np.linalg.norm(
                np.dot(np.dot(ovlp_vecs, np.diag(ovlp_eigs)), ovlp_vecs.T) -
                ovlp) < 1e-10)
            self.ao2loc = np.dot(
                np.dot(ovlp_vecs, np.diag(np.power(ovlp_eigs, -0.5))),
                ovlp_vecs.T)
            self.TI_OK = False  # Check yourself if OK, then overwrite
        if (self._which == 'iao'):
            assert (self.norbs_tot == self.mol.nao_nr()
                    )  # Full active space assumed
            self.ao2loc = iao_helper.localize_iao(self.mol, the_mf)
            if (ao_rotation != None):
                self.ao2loc = np.dot(self.ao2loc, ao_rotation.T)
            self.TI_OK = False  # Check yourself if OK, then overwrite
            #self.molden( 'dump.molden' ) # Debugging mode
        assert (self.loc_ortho() < 1e-8)

        # Stored inverse overlap matrix
        self.ao_ovlp_inv = np.dot(self.ao2loc, self.ao2loc.conjugate().T)
        self.ao_ovlp = the_mf.get_ovlp()
        assert (is_matrix_eye(np.dot(self.ao_ovlp, self.ao_ovlp_inv)))

        # Effective Hamiltonian due to frozen part
        self.frozenDM_mo = np.array(the_mf.mo_occ, copy=True)
        self.frozenDM_mo[self.active ==
                         1] = 0  # Only the frozen MO occupancies nonzero
        self.frozenDM_ao = np.dot(
            np.dot(the_mf.mo_coeff, np.diag(self.frozenDM_mo)),
            the_mf.mo_coeff.T)
        self.frozenJK_ao = self.get_veff_ao(
            self.frozenDM_ao, 0, 0,
            1)  #Last 3 numbers: dm_last, vhf_last, hermi
        if self.frozenJK_ao.ndim == 3:
            self.frozenJK_ao = self.frozenJK_ao[0]
            # Because I gave it a spin-summed 1-RDM, the two spins for JK will necessarily be identical
        self.frozenOEI_ao = self.fullFOCK_ao - self.fullJK_ao + self.frozenJK_ao

        # Localized OEI and ERI
        self.activeCONST = self.mol.energy_nuc() + np.einsum(
            'ij,ij->', self.frozenOEI_ao - 0.5 * self.frozenJK_ao,
            self.frozenDM_ao)
        self.activeOEI = represent_operator_in_basis(self.frozenOEI_ao,
                                                     self.ao2loc)
        self.activeFOCK = represent_operator_in_basis(self.fullFOCK_ao,
                                                      self.ao2loc)
        self.activeVSPIN = np.zeros_like(
            self.activeFOCK)  # FIXME: correct behavior for ROHF init!
        self.activeJKidem = self.activeFOCK - self.activeOEI
        self.activeJKcorr = np.zeros((self.norbs_tot, self.norbs_tot),
                                     dtype=self.activeOEI.dtype)
        self.oneRDM_loc = self.ao2loc.conjugate(
        ).T @ self.ao_ovlp @ self.fullRDM_ao @ self.ao_ovlp @ self.ao2loc
        self.oneSDM_loc = self.ao2loc.conjugate(
        ).T @ self.ao_ovlp @ self.fullSDM_ao @ self.ao_ovlp @ self.ao2loc
        self.oneRDMcorr_loc = np.zeros((self.norbs_tot, self.norbs_tot),
                                       dtype=self.activeOEI.dtype)
        self.loc2idem = np.eye(self.norbs_tot, dtype=self.activeOEI.dtype)
        self.nelec_idem = self.nelec_tot
        self._eri = None
        self.with_df = None
        assert (abs(np.trace(self.oneRDM_loc) - self.nelec_tot) <
                1e-8), '{} {}'.format(np.trace(self.oneRDM_loc),
                                      self.nelec_tot)
        sys.stdout.flush()

        def _is_mem_enough():
            return 2 * (self.norbs_tot**
                        4) / 1e6 + current_memory()[0] < self.max_memory * 0.95

        # Unfortunately, there is currently no way to do the integral transformation directly on the antisymmetrized two-electron
        # integrals, at least none already implemented in PySCF. Therefore the smallest possible memory footprint involves
        # two arrays of fourfold symmetry, which works out to roughly one half of an array with no symmetry
        if hasattr(the_mf, 'with_df') and hasattr(
                the_mf.with_df,
                '_cderi') and the_mf.with_df._cderi is not None:
            print("Found density-fitting three-center integrals scf object")
            loc2ao = self.ao2loc.conjugate().T
            locOao = np.dot(loc2ao, self.ao_ovlp)
            self.with_df = the_mf.with_df
            self.with_df.loc2eri_bas = lambda x: np.dot(self.ao2loc, x)
            self.with_df.loc2eri_op = lambda x: reduce(np.dot, (self.ao2loc, x,
                                                                loc2ao))
            self.with_df.eri2loc_bas = lambda x: np.dot(locOao, x)
            self.with_df.eri2loc_op = lambda x: reduce(np.dot, (loc2ao, x, self
                                                                .ao2loc))
        elif the_mf._eri is not None:
            print("Found eris on scf object")
            loc2ao = self.ao2loc.conjugate().T
            locOao = np.dot(loc2ao, self.ao_ovlp)
            self._eri = the_mf._eri
            self._eri = tag_array(self._eri,
                                  loc2eri_bas=lambda x: np.dot(self.ao2loc, x))
            self._eri = tag_array(
                self._eri,
                loc2eri_op=lambda x: reduce(np.dot, (self.ao2loc, x, loc2ao)))
            self._eri = tag_array(self._eri,
                                  eri2loc_bas=lambda x: np.dot(locOao, x))
            self._eri = tag_array(
                self._eri,
                eri2loc_op=lambda x: reduce(np.dot, (loc2ao, x, self.ao2loc)))
        elif _is_mem_enough():
            print("Storing eris in memory")
            self._eri = ao2mo.restore(
                8,
                ao2mo.outcore.full_iofree(self.mol, self.ao2loc, compact=True),
                self.norbs_tot)
            self._eri = tag_array(self._eri, loc2eri_bas=lambda x: x)
            self._eri = tag_array(self._eri, loc2eri_op=lambda x: x)
            self._eri = tag_array(self._eri, eri2loc_bas=lambda x: x)
            self._eri = tag_array(self._eri, eri2loc_op=lambda x: x)
        else:
            print("Direct calculation")
        sys.stdout.flush()

        # Symmetry information
        try:
            self.loc2symm = [
                orthonormalize_a_basis(scipy.linalg.solve(self.ao2loc, ao2ir))
                for ao2ir in self.mol.symm_orb
            ]
            self.symmetry = self.mol.groupname
            self.wfnsym = the_mf.wfnsym
            self.ir_names = self.mol.irrep_name
            self.ir_ids = self.mol.irrep_id
            self.enforce_symmetry = True
        except (AttributeError, TypeError) as e:
            if self.mol.symmetry: raise (e)
            self.loc2symm = [np.eye(self.norbs_tot)]
            self.symmetry = False
            self.wfnsym = 'A'
            self.ir_names = ['A']
            self.ir_ids = [0]
            self.enforce_symmetry = False
        print("Initial loc2symm nonorthonormality: {}".format(
            measure_basis_nonorthonormality(
                np.concatenate(self.loc2symm, axis=1))))
        for loc2ir1, loc2ir2 in itertools.combinations(self.loc2symm, 2):
            proj = loc2ir1 @ loc2ir1.conjugate().T
            loc2ir2[:, :] -= proj @ loc2ir2
        for loc2ir in self.loc2symm:
            loc2ir[:, :] = orthonormalize_a_basis(loc2ir)
        print("Final loc2symm nonorthonormality: {}".format(
            measure_basis_nonorthonormality(
                np.concatenate(self.loc2symm, axis=1))))
Ejemplo n.º 25
0
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mol = mf.mol
    if not mol.symmetry:
        return uhf.analyze(mf, verbose, with_meta_lowdin, **kwargs)

    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    ovlp_ao = mf.get_ovlp()
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        nirrep = len(mol.irrep_id)
        ovlp_ao = mf.get_ovlp()
        orbsyma, orbsymb = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False)
        tot_sym = 0
        noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id]
        noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id]
        for i, ir in enumerate(mol.irrep_id):
            if (noccsa[i]+noccsb[i]) % 2:
                tot_sym ^= ir
        if mol.groupname in ('Dooh', 'Coov', 'SO3'):
            log.note('TODO: total wave-function symmetry for %s', mol.groupname)
        else:
            log.note('Wave-function symmetry = %s',
                     symm.irrep_id2name(mol.groupname, tot_sym))
        log.note('alpha occupancy for each irrep:  '+(' %4s'*nirrep),
                 *mol.irrep_name)
        log.note('                                 '+(' %4d'*nirrep),
                 *noccsa)
        log.note('beta  occupancy for each irrep:  '+(' %4s'*nirrep),
                 *mol.irrep_name)
        log.note('                                 '+(' %4d'*nirrep),
                 *noccsb)

        log.note('**** MO energy ****')
        irname_full = {}
        for k, ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+MO_BASE, irname_full[j], irorbcnt[j],
                     mo_energy[0][k], mo_occ[0][k])
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('beta  MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+MO_BASE, irname_full[j], irorbcnt[j],
                     mo_energy[1][k], mo_occ[1][k])

    if mf.verbose >= logger.DEBUG:
        label = mol.ao_labels()
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' %
                           (k+MO_BASE, irname_full[j], irorbcnt[j]))
        if with_meta_lowdin:
            log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
            c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
            mo = c_inv.dot(mo_coeff[0])
        else:
            log.debug(' ** alpha MO coefficients (expansion on AOs) **')
            mo = mo_coeff[0]
        dump_mat.dump_rec(mf.stdout, mo, label, start=MO_BASE, **kwargs)

        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' %
                           (k+MO_BASE, irname_full[j], irorbcnt[j]))
        if with_meta_lowdin:
            log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **')
            mo = c_inv.dot(mo_coeff[1])
        else:
            log.debug(' ** beta MO coefficients (expansion on AOs) **')
            mo = mo_coeff[1]
        dump_mat.dump_rec(mol.stdout, mo, label, molabel, start=MO_BASE, **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
    else:
        pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log)
    dip = mf.dip_moment(mol, dm, verbose=log)
    return pop_and_charge, dip
Ejemplo n.º 26
0
    def analyze(self, verbose=logger.DEBUG):
        from pyscf.lo import orth
        from pyscf.tools import dump_mat
        mo_energy = self.mo_energy
        mo_occ = self.mo_occ
        mo_coeff = self.mo_coeff
        log = logger.Logger(self.stdout, verbose)
        mol = self.mol
        nirrep = len(mol.irrep_id)
        ovlp_ao = self.get_ovlp()
        orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff,
                                     s=ovlp_ao)
        orbsym = numpy.array(orbsym)
        wfnsym = 0
        ndoccs = []
        nsoccs = []
        for k,ir in enumerate(mol.irrep_id):
            ndoccs.append(sum(orbsym[mo_occ==2] == ir))
            nsoccs.append(sum(orbsym[mo_occ==1] == ir))
            if nsoccs[k] % 2:
                wfnsym ^= ir
        if mol.groupname in ('Dooh', 'Coov'):
            log.info('TODO: total symmetry for %s', mol.groupname)
        else:
            log.info('total symmetry = %s',
                     symm.irrep_id2name(mol.groupname, wfnsym))
        log.info('occupancy for each irrep:  ' + (' %4s'*nirrep),
                 *mol.irrep_name)
        log.info('double occ                 ' + (' %4d'*nirrep), *ndoccs)
        log.info('single occ                 ' + (' %4d'*nirrep), *nsoccs)
        log.info('**** MO energy ****')
        irname_full = {}
        for k,ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        if self._focka_ao is None:
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g',
                         k+1, irname_full[j], irorbcnt[j],
                         mo_energy[k], mo_occ[k])
        else:
            mo_ea = numpy.einsum('ik,ik->k', mo_coeff, self._focka_ao.dot(mo_coeff))
            mo_eb = numpy.einsum('ik,ik->k', mo_coeff, self._fockb_ao.dot(mo_coeff))
            log.note('                          Roothaan           | alpha              | beta')
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                log.note('MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g',
                         k+1, irname_full[j], irorbcnt[j],
                         mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k])

        if verbose >= logger.DEBUG:
            label = mol.spheric_labels(True)
            molabel = []
            irorbcnt = {}
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
            c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
            dump_mat.dump_rec(self.stdout, c, label, molabel, start=1)

        dm = self.make_rdm1(mo_coeff, mo_occ)
        return self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=verbose)
Ejemplo n.º 27
0
def cas_natorb(mc, mo_coeff=None, ci=None, eris=None, sort=False,
               casdm1=None, verbose=None):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.  Be careful with this
            option since the resultant natural orbitals might have the
            different symmetry to the irreps indicated by CASSCF.orbsym

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mc.stdout, mc.verbose)
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        idx = numpy.argsort(occ)
        occ = occ[idx]
        ucas = ucas[:,idx]

    occ = -occ

# where_natorb gives the location of the natural orbital for the input cas
# orbitals.  gen_strings4orblist map thes sorted strings (on CAS orbital) to
# the unsorted determinant strings (on natural orbital). e.g.  (3o,2e) system
#       CAS orbital      1  2  3
#       natural orbital  3  1  2        <= by mo_1to1map
#       CASorb-strings   0b011, 0b101, 0b110
#                    ==  (1,2), (1,3), (2,3)
#       natorb-strings   (3,1), (3,2), (1,2)
#                    ==  0B101, 0B110, 0B011    <= by gen_strings4orblist
# then argsort to translate the string representation to the address
#       [2(=0B011), 0(=0B101), 1(=0B110)]
# to indicate which CASorb-strings address to be loaded in each natorb-strings slot
    where_natorb = mo_1to1map(ucas)
    #guide_stringsa = fci.cistring.gen_strings4orblist(where_natorb, nelecas[0])
    #guide_stringsb = fci.cistring.gen_strings4orblist(where_natorb, nelecas[1])
    #old_det_idxa = numpy.argsort(guide_stringsa)
    #old_det_idxb = numpy.argsort(guide_stringsb)
    #ci0 = ci[old_det_idxa[:,None],old_det_idxb]
    if isinstance(ci, numpy.ndarray):
        ci0 = fci.addons.reorder(ci, nelecas, where_natorb)
    elif isinstance(ci, (tuple, list)) and isinstance(ci[0], numpy.ndarray):
        # for state-average eigenfunctions
        ci0 = [fci.addons.reorder(x, nelecas, where_natorb) for x in ci]
    else:
        log.info('FCI vector not available, so not using old wavefunction as initial guess')
        ci0 = None

# restore phase, to ensure the reordered ci vector is the correct initial guess
    for i, k in enumerate(where_natorb):
        if ucas[i,k] < 0:
            ucas[:,k] *= -1
    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:,ncore:nocc] = numpy.dot(mo_coeff[:,ncore:nocc], ucas)
    if log.verbose >= logger.INFO:
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(occ))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        label = mc.mol.spheric_labels(True)
        orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff1[:,ncore:nocc]))
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:,ncore:nocc].T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f',
                         ncore+i+1, j+1, s[i,j])

    mocas = mo_coeff1[:,ncore:nocc]
    h1eff = reduce(numpy.dot, (mocas.T, mc.get_hcore(), mocas))
    if eris is not None and hasattr(eris, 'ppaa'):
        h1eff += reduce(numpy.dot, (ucas.T, eris.vhf_c[ncore:nocc,ncore:nocc], ucas))
        aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc,ncore:nocc,:,:], ncas)
        aaaa = ao2mo.incore.full(aaaa, ucas)
    else:
        dm_core = numpy.dot(mo_coeff[:,:ncore]*2, mo_coeff[:,:ncore].T)
        vj, vk = mc._scf.get_jk(mc.mol, dm_core)
        h1eff += reduce(numpy.dot, (mocas.T, vj-vk*.5, mocas))
        aaaa = ao2mo.kernel(mc.mol, mocas)
    e_cas, fcivec = mc.fcisolver.kernel(h1eff, aaaa, ncas, nelecas, ci0=ci0)
    log.debug('In Natural orbital, CI energy = %.12g', e_cas)
    return mo_coeff1, fcivec, occ
Ejemplo n.º 28
0
def analyze(casscf, mo_coeff=None, ci=None, verbose=logger.INFO):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    if mo_coeff is None: mo_coeff = casscf.mo_coeff
    if ci is None: ci = casscf.ci
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(casscf.stdout, verbose)
    nelecas = casscf.nelecas
    ncas = casscf.ncas
    ncore = casscf.ncore
    nocc = ncore + ncas
    label = casscf.mol.spheric_labels(True)

    if hasattr(casscf.fcisolver, 'make_rdm1s'):
        casdm1a, casdm1b = casscf.fcisolver.make_rdm1s(ci, ncas, nelecas)
        casdm1 = casdm1a + casdm1b
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1b = numpy.dot(mocore, mocore.T)
        dm1a = dm1b + reduce(numpy.dot, (mocas, casdm1a, mocas.T))
        dm1b += reduce(numpy.dot, (mocas, casdm1b, mocas.T))
        dm1 = dm1a + dm1b
        if log.verbose >= logger.DEBUG1:
            log.info('alpha density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1a, label)
            log.info('beta density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1b, label)
    else:
        casdm1 = casscf.fcisolver.make_rdm1(ci, ncas, nelecas)
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a

    if log.verbose >= logger.INFO:
        ovlp_ao = casscf._scf.get_ovlp()
        # note the last two args of ._eig for mc1step_symm
        occ, ucas = casscf._eig(-casdm1, ncore, nocc)
        log.info('Natural occ %s', str(-occ))
        for i, k in enumerate(numpy.argmax(abs(ucas), axis=0)):
            if ucas[k,i] < 0:
                ucas[:,i] *= -1
        orth_coeff = orth.orth_ao(casscf.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff[:,ncore:nocc], ucas))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if casscf._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (casscf.mo_coeff.T, ovlp_ao, casscf._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<mo-mcscf|mo-hf> %d  %d  %12.8f', i+1, j+1, s[i,j])

        if ci is not None and numpy.ndim(ci) >= 2:
            log.info('** Largest CI components **')
            if ci[0].ndim == 2:
                for i, state in enumerate(ci):
                    log.info(' string alpha, string beta, state %d CI coefficients', i)
                    for c,ia,ib in fci.addons.large_ci(state, casscf.ncas, casscf.nelecas):
                        log.info('  %9s    %9s    %.12f', ia, ib, c)
            else:
                log.info(' string alpha, string beta, CI coefficients')
                for c,ia,ib in fci.addons.large_ci(ci, casscf.ncas, casscf.nelecas):
                    log.info('  %9s    %9s    %.12f', ia, ib, c)

        casscf._scf.mulliken_meta(casscf.mol, dm1, s=ovlp_ao, verbose=log)
    return dm1a, dm1b
Ejemplo n.º 29
0
def analyze(mf,
            verbose=logger.DEBUG,
            with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Occupancy for each irreps; Mulliken population analysis
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mol = mf.mol
    if not mol.symmetry:
        return hf.analyze(mf, verbose, with_meta_lowdin, **kwargs)

    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    ovlp_ao = mf.get_ovlp()
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        nirrep = len(mol.irrep_id)
        orbsym = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False)
        wfnsym = 0
        noccs = [sum(orbsym[mo_occ > 0] == ir) for ir in mol.irrep_id]
        if mol.groupname in ('SO3', 'Dooh', 'Coov'):
            log.note('TODO: total wave-function symmetry for %s',
                     mol.groupname)
        else:
            log.note('Wave-function symmetry = %s',
                     symm.irrep_id2name(mol.groupname, wfnsym))
        log.note('occupancy for each irrep:  ' + (' %4s' * nirrep),
                 *mol.irrep_name)
        log.note('                           ' + (' %4d' * nirrep), *noccs)
        log.note('**** MO energy ****')
        irname_full = {}
        for k, ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        for k, j in enumerate(orbsym):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k + MO_BASE,
                     irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k])

    if log.verbose >= logger.DEBUG:
        label = mol.ao_labels()
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsym):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' %
                           (k + MO_BASE, irname_full[j], irorbcnt[j]))
        if with_meta_lowdin:
            log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
            c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
        else:
            log.debug(' ** MO coefficients (expansion on AOs) **')
            c = mo_coeff
        dump_mat.dump_rec(mf.stdout,
                          c,
                          label,
                          molabel,
                          start=MO_BASE,
                          **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
    else:
        pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log)
    dip = mf.dip_moment(mol, dm, verbose=log)
    return pop_and_charge, dip
Ejemplo n.º 30
0
def analyze(casscf, mo_coeff=None, ci=None, verbose=None,
            large_ci_tol=LARGE_CI_TOL, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.mcscf import addons
    log = logger.new_logger(casscf, verbose)

    if mo_coeff is None: mo_coeff = casscf.mo_coeff
    if ci is None: ci = casscf.ci
    nelecas = casscf.nelecas
    ncas = casscf.ncas
    ncore = casscf.ncore
    nocc = ncore + ncas
    mocore = mo_coeff[:,:ncore]
    mocas = mo_coeff[:,ncore:nocc]

    label = casscf.mol.ao_labels()
    if (isinstance(ci, (list, tuple)) and
        not isinstance(casscf.fcisolver, addons.StateAverageFCISolver)):
        log.warn('Mulitple states found in CASCI/CASSCF solver. Density '
                 'matrix of first state is generated in .analyze() function.')
        civec = ci[0]
    else:
        civec = ci
    if getattr(casscf.fcisolver, 'make_rdm1s', None):
        casdm1a, casdm1b = casscf.fcisolver.make_rdm1s(civec, ncas, nelecas)
        casdm1 = casdm1a + casdm1b
        dm1b = numpy.dot(mocore, mocore.T)
        dm1a = dm1b + reduce(numpy.dot, (mocas, casdm1a, mocas.T))
        dm1b += reduce(numpy.dot, (mocas, casdm1b, mocas.T))
        dm1 = dm1a + dm1b
        if log.verbose >= logger.DEBUG2:
            log.info('alpha density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1a, label, **kwargs)
            log.info('beta density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1b, label, **kwargs)
    else:
        casdm1 = casscf.fcisolver.make_rdm1(civec, ncas, nelecas)
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a

    if log.verbose >= logger.INFO:
        ovlp_ao = casscf._scf.get_ovlp()
        # note the last two args of ._eig for mc1step_symm
        occ, ucas = casscf._eig(-casdm1, ncore, nocc)
        log.info('Natural occ %s', str(-occ))
        mocas = numpy.dot(mocas, ucas)
        if with_meta_lowdin:
            log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
            orth_coeff = orth.orth_ao(casscf.mol, 'meta_lowdin', s=ovlp_ao)
            mocas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas))
        else:
            log.info('Natural orbital (expansion on AOs) in CAS space')
        dump_mat.dump_rec(log.stdout, mocas, label, start=1, **kwargs)
        if log.verbose >= logger.DEBUG2:
            if not casscf.natorb:
                log.debug2('NOTE: mc.mo_coeff in active space is different to '
                           'the natural orbital coefficients printed in above.')
            if with_meta_lowdin:
                c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
                log.debug2('MCSCF orbital (expansion on meta-Lowdin AOs)')
            else:
                c = mo_coeff
                log.debug2('MCSCF orbital (expansion on AOs)')
            dump_mat.dump_rec(log.stdout, c, label, start=1, **kwargs)

        if casscf._scf.mo_coeff is not None:
            addons.map2hf(casscf, casscf._scf.mo_coeff)

        if getattr(casscf.fcisolver, 'large_ci', None) and ci is not None:
            log.info('** Largest CI components **')
            if isinstance(ci, (tuple, list)):
                for i, civec in enumerate(ci):
                    res = casscf.fcisolver.large_ci(civec, casscf.ncas, casscf.nelecas,
                                                    large_ci_tol, return_strs=False)
                    log.info('  [alpha occ-orbitals] [beta occ-orbitals]  state %-3d CI coefficient', i)
                    for c,ia,ib in res:
                        log.info('  %-20s %-30s %.12f', ia, ib, c)
            else:
                log.info('  [alpha occ-orbitals] [beta occ-orbitals]            CI coefficient')
                res = casscf.fcisolver.large_ci(ci, casscf.ncas, casscf.nelecas,
                                                large_ci_tol, return_strs=False)
                for c,ia,ib in res:
                    log.info('  %-20s %-30s %.12f', ia, ib, c)

        if with_meta_lowdin:
            casscf._scf.mulliken_meta(casscf.mol, dm1, s=ovlp_ao, verbose=log)
        else:
            casscf._scf.mulliken_pop(casscf.mol, dm1, s=ovlp_ao, verbose=log)
    return dm1a, dm1b
Ejemplo n.º 31
0
def analyze(casscf, mo_coeff=None, ci=None, verbose=None,
            large_ci_tol=LARGE_CI_TOL, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.mcscf import addons
    log = logger.new_logger(casscf, verbose)

    if mo_coeff is None: mo_coeff = casscf.mo_coeff
    if ci is None: ci = casscf.ci
    nelecas = casscf.nelecas
    ncas = casscf.ncas
    ncore = casscf.ncore
    nocc = ncore + ncas
    mocore = mo_coeff[:,:ncore]
    mocas = mo_coeff[:,ncore:nocc]

    label = casscf.mol.ao_labels()
    if (isinstance(ci, (list, tuple, RANGE_TYPE)) and
        not isinstance(casscf.fcisolver, addons.StateAverageFCISolver)):
        log.warn('Mulitple states found in CASCI/CASSCF solver. Density '
                 'matrix of the first state is generated in .analyze() function.')
        civec = ci[0]
    else:
        civec = ci
    if getattr(casscf.fcisolver, 'make_rdm1s', None):
        casdm1a, casdm1b = casscf.fcisolver.make_rdm1s(civec, ncas, nelecas)
        casdm1 = casdm1a + casdm1b
        dm1b = numpy.dot(mocore, mocore.T)
        dm1a = dm1b + reduce(numpy.dot, (mocas, casdm1a, mocas.T))
        dm1b += reduce(numpy.dot, (mocas, casdm1b, mocas.T))
        dm1 = dm1a + dm1b
        if log.verbose >= logger.DEBUG2:
            log.info('alpha density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1a, label, **kwargs)
            log.info('beta density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1b, label, **kwargs)
    else:
        casdm1 = casscf.fcisolver.make_rdm1(civec, ncas, nelecas)
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a

    if log.verbose >= logger.INFO:
        ovlp_ao = casscf._scf.get_ovlp()
        # note the last two args of ._eig for mc1step_symm
        occ, ucas = casscf._eig(-casdm1, ncore, nocc)
        log.info('Natural occ %s', str(-occ))
        mocas = numpy.dot(mocas, ucas)
        if with_meta_lowdin:
            log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
            orth_coeff = orth.orth_ao(casscf.mol, 'meta_lowdin', s=ovlp_ao)
            mocas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mocas))
        else:
            log.info('Natural orbital (expansion on AOs) in CAS space')
        dump_mat.dump_rec(log.stdout, mocas, label, start=1, **kwargs)
        if log.verbose >= logger.DEBUG2:
            if not casscf.natorb:
                log.debug2('NOTE: mc.mo_coeff in active space is different to '
                           'the natural orbital coefficients printed in above.')
            if with_meta_lowdin:
                c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
                log.debug2('MCSCF orbital (expansion on meta-Lowdin AOs)')
            else:
                c = mo_coeff
                log.debug2('MCSCF orbital (expansion on AOs)')
            dump_mat.dump_rec(log.stdout, c, label, start=1, **kwargs)

        if casscf._scf.mo_coeff is not None:
            addons.map2hf(casscf, casscf._scf.mo_coeff)

        if (ci is not None and
            (getattr(casscf.fcisolver, 'large_ci', None) or
             getattr(casscf.fcisolver, 'states_large_ci', None))):
            log.info('** Largest CI components **')
            if isinstance(ci, (list, tuple, RANGE_TYPE)):
                if hasattr(casscf.fcisolver, 'states_large_ci'):
                    # defined in state_average_mix_ mcscf object
                    res = casscf.fcisolver.states_large_ci(ci, casscf.ncas, casscf.nelecas,
                                                           large_ci_tol, return_strs=False)
                else:
                    res = [casscf.fcisolver.large_ci(civec, casscf.ncas, casscf.nelecas,
                                                     large_ci_tol, return_strs=False)
                           for civec in ci]
                for i, civec in enumerate(ci):
                    log.info('  [alpha occ-orbitals] [beta occ-orbitals]  state %-3d CI coefficient', i)
                    for c,ia,ib in res[i]:
                        log.info('  %-20s %-30s %.12f', ia, ib, c)
            else:
                log.info('  [alpha occ-orbitals] [beta occ-orbitals]            CI coefficient')
                res = casscf.fcisolver.large_ci(ci, casscf.ncas, casscf.nelecas,
                                                large_ci_tol, return_strs=False)
                for c,ia,ib in res:
                    log.info('  %-20s %-30s %.12f', ia, ib, c)

        if with_meta_lowdin:
            casscf._scf.mulliken_meta(casscf.mol, dm1, s=ovlp_ao, verbose=log)
        else:
            casscf._scf.mulliken_pop(casscf.mol, dm1, s=ovlp_ao, verbose=log)
    return dm1a, dm1b
Ejemplo n.º 32
0
def cas_natorb(mc, mo_coeff=None, ci=None, eris=None, sort=False,
               casdm1=None, verbose=None, with_meta_lowdin=WITH_META_LOWDIN):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn
    accordingly

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    log = logger.new_logger(mc, verbose)
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    nmo = mo_coeff.shape[1]
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    # orbital symmetry is reserved in this _eig call
    cas_occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        casorb_idx = numpy.argsort(cas_occ.round(9), kind='mergesort')
        cas_occ = cas_occ[casorb_idx]
        ucas = ucas[:,casorb_idx]

    cas_occ = -cas_occ
    mo_occ = numpy.zeros(mo_coeff.shape[1])
    mo_occ[:ncore] = 2
    mo_occ[ncore:nocc] = cas_occ

    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:,ncore:nocc] = numpy.dot(mo_coeff[:,ncore:nocc], ucas)
    if getattr(mo_coeff, 'orbsym', None) is not None:
        orbsym = numpy.copy(mo_coeff.orbsym)
        if sort:
            orbsym[ncore:nocc] = orbsym[ncore:nocc][casorb_idx]
        mo_coeff1 = lib.tag_array(mo_coeff1, orbsym=orbsym)
    else:
        orbsym = numpy.zeros(nmo, dtype=int)

    # When occupancies of active orbitals equal to 2 or 0, these orbitals
    # need to be canonicalized along with inactive(core or virtual) orbitals
    # using general Fock matrix. Because they are strongly coupled with
    # inactive orbitals, the 0th order Hamiltonian of MRPT methods can be
    # strongly affected. Numerical uncertainty may be found in the perturbed
    # correlation energy.
    # See issue https://github.com/pyscf/pyscf/issues/1041
    occ2_idx = numpy.where(2 - cas_occ < FRAC_OCC_THRESHOLD)[0]
    occ0_idx = numpy.where(cas_occ < FRAC_OCC_THRESHOLD)[0]
    if occ2_idx.size > 0 or occ0_idx.size > 0:
        fock_ao = mc.get_fock(mo_coeff, ci, eris, casdm1, verbose)

        def _diag_subfock_(idx):
            c = mo_coeff1[:,idx]
            fock = reduce(numpy.dot, (c.conj().T, fock_ao, c))
            w, c = mc._eig(fock, None, None, orbsym[idx])
            mo_coeff1[:,idx] = mo_coeff1[:,idx].dot(c)

        if occ2_idx.size > 0:
            log.warn('Active orbitals %s (occs = %s) are canonicalized with core orbitals',
                     occ2_idx, cas_occ[occ2_idx])
            full_occ2_idx = numpy.append(numpy.arange(ncore), ncore + occ2_idx)
            _diag_subfock_(full_occ2_idx)
        if occ0_idx.size > 0:
            log.warn('Active orbitals %s (occs = %s) are canonicalized with external orbitals',
                     occ0_idx, cas_occ[occ0_idx])
            full_occ0_idx = numpy.append(ncore + occ0_idx, numpy.arange(nocc, nmo))
            _diag_subfock_(full_occ0_idx)

    # Rotate CI according to the unitary coefficients ucas if applicable
    fcivec = None
    if getattr(mc.fcisolver, 'transform_ci_for_orbital_rotation', None):
        if isinstance(ci, numpy.ndarray):
            fcivec = mc.fcisolver.transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)
        elif (isinstance(ci, (list, tuple)) and
              all(isinstance(x[0], numpy.ndarray) for x in ci)):
            fcivec = [mc.fcisolver.transform_ci_for_orbital_rotation(x, ncas, nelecas, ucas)
                      for x in ci]
    elif getattr(mc.fcisolver, 'states_transform_ci_for_orbital_rotation', None):
        fcivec = mc.fcisolver.states_transform_ci_for_orbital_rotation(ci, ncas, nelecas, ucas)

    # Rerun fcisolver to get wavefunction if it cannot be transformed from
    # existed one.
    if fcivec is None:
        log.info('FCI vector not available, call CASCI to update wavefunction')
        mocas = mo_coeff1[:,ncore:nocc]
        hcore = mc.get_hcore()
        dm_core = numpy.dot(mo_coeff1[:,:ncore]*2, mo_coeff1[:,:ncore].conj().T)
        ecore = mc.energy_nuc()
        ecore+= numpy.einsum('ij,ji', hcore, dm_core)
        h1eff = reduce(numpy.dot, (mocas.conj().T, hcore, mocas))
        if getattr(eris, 'ppaa', None) is not None:
            ecore += eris.vhf_c[:ncore,:ncore].trace()
            h1eff += reduce(numpy.dot, (ucas.conj().T, eris.vhf_c[ncore:nocc,ncore:nocc], ucas))
            aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc,ncore:nocc,:,:], ncas)
            aaaa = ao2mo.incore.full(aaaa, ucas)
        else:
            if getattr(mc, 'with_df', None):
                aaaa = mc.with_df.ao2mo(mocas)
            else:
                aaaa = ao2mo.kernel(mc.mol, mocas)
            corevhf = mc.get_veff(mc.mol, dm_core)
            ecore += numpy.einsum('ij,ji', dm_core, corevhf) * .5
            h1eff += reduce(numpy.dot, (mocas.conj().T, corevhf, mocas))


        # See label_symmetry_ function in casci_symm.py which initialize the
        # orbital symmetry information in fcisolver.  This orbital symmetry
        # labels should be reordered to match the sorted active space orbitals.
        if sort and getattr(mo_coeff1, 'orbsym', None) is not None:
            mc.fcisolver.orbsym = mo_coeff1.orbsym[ncore:nocc]

        max_memory = max(400, mc.max_memory-lib.current_memory()[0])
        e, fcivec = mc.fcisolver.kernel(h1eff, aaaa, ncas, nelecas, ecore=ecore,
                                        max_memory=max_memory, verbose=log)
        log.debug('In Natural orbital, CASCI energy = %s', e)

    if log.verbose >= logger.INFO:
        ovlp_ao = mc._scf.get_ovlp()
        # where_natorb gives the new locations of the natural orbitals
        where_natorb = mo_1to1map(ucas)
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(cas_occ))
        if with_meta_lowdin:
            log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
            label = mc.mol.ao_labels()
            orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
            mo_cas = reduce(numpy.dot, (orth_coeff.conj().T, ovlp_ao, mo_coeff1[:,ncore:nocc]))
        else:
            log.info('Natural orbital (expansion on AOs) in CAS space')
            label = mc.mol.ao_labels()
            mo_cas = mo_coeff1[:,ncore:nocc]
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:,ncore:nocc].conj().T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f',
                         ncore+i+1, j+1, s[i,j])
    return mo_coeff1, fcivec, mo_occ
Ejemplo n.º 33
0
def cas_natorb(mc,
               mo_coeff=None,
               ci=None,
               eris=None,
               sort=False,
               casdm1=None,
               verbose=None):
    '''Transform active orbitals to natrual orbitals, and update the CI wfn

    Args:
        mc : a CASSCF/CASCI object or RHF object

    Kwargs:
        sort : bool
            Sort natural orbitals wrt the occupancy.

    Returns:
        A tuple, the first item is natural orbitals, the second is updated CI
        coefficients, the third is the natural occupancy associated to the
        natural orbitals.
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    from pyscf.tools.mo_mapping import mo_1to1map
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mc.stdout, mc.verbose)
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    if ci is None: ci = mc.ci
    ncore = mc.ncore
    ncas = mc.ncas
    nocc = ncore + ncas
    nelecas = mc.nelecas
    if casdm1 is None:
        casdm1 = mc.fcisolver.make_rdm1(ci, ncas, nelecas)
    # orbital symmetry is reserved in this _eig call
    occ, ucas = mc._eig(-casdm1, ncore, nocc)
    if sort:
        casorb_idx = numpy.argsort(occ)
        occ = occ[casorb_idx]
        ucas = ucas[:, casorb_idx]


# restore phase
# where_natorb gives the location of the natural orbital for the input cas
# orbitals.  gen_strings4orblist map thes sorted strings (on CAS orbital) to
# the unsorted determinant strings (on natural orbital). e.g.  (3o,2e) system
#       CAS orbital      1  2  3
#       natural orbital  3  1  2        <= by mo_1to1map
#       CASorb-strings   0b011, 0b101, 0b110
#                    ==  (1,2), (1,3), (2,3)
#       natorb-strings   (3,1), (3,2), (1,2)
#                    ==  0B101, 0B110, 0B011    <= by gen_strings4orblist
# then argsort to translate the string representation to the address
#       [2(=0B011), 0(=0B101), 1(=0B110)]
# to indicate which CASorb-strings address to be loaded in each natorb-strings slot
    where_natorb = mo_1to1map(ucas)
    for i, k in enumerate(where_natorb):
        if ucas[i, k] < 0:
            ucas[:, k] *= -1

    occ = -occ
    mo_occ = numpy.zeros(mo_coeff.shape[1])
    mo_occ[:ncore] = 2
    mo_occ[ncore:nocc] = occ

    if isinstance(ci, numpy.ndarray):
        fcivec = fci.addons.transform_ci_for_orbital_rotation(
            ci, ncas, nelecas, ucas)
    elif isinstance(ci, (tuple, list)) and isinstance(ci[0], numpy.ndarray):
        # for state-average eigenfunctions
        fcivec = [
            fci.addons.transform_ci_for_orbital_rotation(
                x, ncas, nelecas, ucas) for x in ci
        ]
    else:
        log.info('FCI vector not available, call CASCI for wavefunction')
        mocas = mo_coeff[:, ncore:nocc]
        h1eff = reduce(numpy.dot, (mocas.T, mc.get_hcore(), mocas))
        if eris is not None and hasattr(eris, 'ppaa'):
            h1eff += reduce(numpy.dot,
                            (ucas.T, eris.vhf_c[ncore:nocc, ncore:nocc], ucas))
            aaaa = ao2mo.restore(4, eris.ppaa[ncore:nocc, ncore:nocc, :, :],
                                 ncas)
            aaaa = ao2mo.incore.full(aaaa, ucas)
        else:
            dm_core = numpy.dot(mo_coeff[:, :ncore] * 2, mo_coeff[:, :ncore].T)
            vj, vk = mc._scf.get_jk(mc.mol, dm_core)
            h1eff += reduce(numpy.dot, (mocas.T, vj - vk * .5, mocas))
            aaaa = ao2mo.kernel(mc.mol, mocas)
        max_memory = max(400, mc.max_memory - lib.current_memory()[0])
        e_cas, fcivec = mc.fcisolver.kernel(h1eff,
                                            aaaa,
                                            ncas,
                                            nelecas,
                                            max_memory=max_memory,
                                            verbose=log)
        log.debug('In Natural orbital, CI energy = %.12g', e_cas)

    mo_coeff1 = mo_coeff.copy()
    mo_coeff1[:, ncore:nocc] = numpy.dot(mo_coeff[:, ncore:nocc], ucas)
    if hasattr(mo_coeff, 'orbsym'):
        orbsym = numpy.copy(mo_coeff.orbsym)
        if sort:
            orbsym[ncore:nocc] = orbsym[ncore:nocc][casorb_idx]
        mo_coeff1 = lib.tag_array(mo_coeff1, orbsym=orbsym)

    if log.verbose >= logger.INFO:
        ovlp_ao = mc._scf.get_ovlp()
        log.debug('where_natorb %s', str(where_natorb))
        log.info('Natural occ %s', str(occ))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        label = mc.mol.ao_labels()
        orth_coeff = orth.orth_ao(mc.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot,
                        (orth_coeff.T, ovlp_ao, mo_coeff1[:, ncore:nocc]))
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1)

        if mc._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (mo_coeff1[:, ncore:nocc].T,
                                   mc._scf.get_ovlp(), mc._scf.mo_coeff))
            idx = numpy.argwhere(abs(s) > .4)
            for i, j in idx:
                log.info('<CAS-nat-orb|mo-hf>  %d  %d  %12.8f', ncore + i + 1,
                         j + 1, s[i, j])
    return mo_coeff1, fcivec, mo_occ
Ejemplo n.º 34
0
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mol = mf.mol
    if not mol.symmetry:
        return uhf.analyze(mf, verbose, with_meta_lowdin, **kwargs)

    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    ovlp_ao = mf.get_ovlp()
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        nirrep = len(mol.irrep_id)
        ovlp_ao = mf.get_ovlp()
        orbsyma, orbsymb = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False)
        tot_sym = 0
        noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id]
        noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id]
        for i, ir in enumerate(mol.irrep_id):
            if (noccsa[i]+noccsb[i]) % 2:
                tot_sym ^= ir
        if mol.groupname in ('Dooh', 'Coov', 'SO3'):
            log.note('TODO: total wave-function symmetry for %s', mol.groupname)
        else:
            log.note('Wave-function symmetry = %s',
                     symm.irrep_id2name(mol.groupname, tot_sym))
        log.note('alpha occupancy for each irrep:  '+(' %4s'*nirrep),
                 *mol.irrep_name)
        log.note('                                 '+(' %4d'*nirrep),
                 *noccsa)
        log.note('beta  occupancy for each irrep:  '+(' %4s'*nirrep),
                 *mol.irrep_name)
        log.note('                                 '+(' %4d'*nirrep),
                 *noccsb)

        log.note('**** MO energy ****')
        irname_full = {}
        for k, ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+MO_BASE, irname_full[j], irorbcnt[j],
                     mo_energy[0][k], mo_occ[0][k])
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('beta  MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+MO_BASE, irname_full[j], irorbcnt[j],
                     mo_energy[1][k], mo_occ[1][k])

    if mf.verbose >= logger.DEBUG:
        label = mol.ao_labels()
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' %
                           (k+MO_BASE, irname_full[j], irorbcnt[j]))
        if with_meta_lowdin:
            log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **')
            orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
            c_inv = numpy.dot(orth_coeff.conj().T, ovlp_ao)
            mo = c_inv.dot(mo_coeff[0])
        else:
            log.debug(' ** alpha MO coefficients (expansion on AOs) **')
            mo = mo_coeff[0]
        dump_mat.dump_rec(mf.stdout, mo, label, start=MO_BASE, **kwargs)

        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' %
                           (k+MO_BASE, irname_full[j], irorbcnt[j]))
        if with_meta_lowdin:
            log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **')
            mo = c_inv.dot(mo_coeff[1])
        else:
            log.debug(' ** beta MO coefficients (expansion on AOs) **')
            mo = mo_coeff[1]
        dump_mat.dump_rec(mol.stdout, mo, label, molabel, start=MO_BASE, **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
    else:
        pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log)
    dip = mf.dip_moment(mol, dm, verbose=log)
    return pop_and_charge, dip
Ejemplo n.º 35
0
def analyze(mf, verbose=logger.DEBUG):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    mol = mf.mol
    log = pyscf.lib.logger.Logger(mf.stdout, verbose)
    nirrep = len(mol.irrep_id)
    ovlp_ao = mf.get_ovlp()
    orbsyma = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb,
                                  mo_coeff[0], s=ovlp_ao)
    orbsymb = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb,
                                  mo_coeff[1], s=ovlp_ao)
    orbsyma = numpy.array(orbsyma)
    orbsymb = numpy.array(orbsymb)
    tot_sym = 0
    noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id]
    noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id]
    for i, ir in enumerate(mol.irrep_id):
        if (noccsa[i]+noccsb[i]) % 2:
            tot_sym ^= ir
    if mol.groupname in ('Dooh', 'Coov', 'SO3'):
        log.note('TODO: total symmetry for %s', mol.groupname)
    else:
        log.note('total symmetry = %s',
                 symm.irrep_id2name(mol.groupname, tot_sym))
    log.note('alpha occupancy for each irrep:  '+(' %4s'*nirrep),
             *mol.irrep_name)
    log.note('                                 '+(' %4d'*nirrep),
             *noccsa)
    log.note('beta  occupancy for each irrep:  '+(' %4s'*nirrep),
             *mol.irrep_name)
    log.note('                                 '+(' %4d'*nirrep),
             *noccsb)

    ss, s = mf.spin_square((mo_coeff[0][:,mo_occ[0]>0],
                            mo_coeff[1][:,mo_occ[1]>0]), ovlp_ao)
    log.note('multiplicity <S^2> = %.8g  2S+1 = %.8g', ss, s)

    if verbose >= logger.NOTE:
        log.note('**** MO energy ****')
        irname_full = {}
        for k, ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+1, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k])
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('beta  MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+1, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k])

    ovlp_ao = mf.get_ovlp()
    if mf.verbose >= logger.DEBUG:
        label = mol.spheric_labels(True)
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
        log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **')
        orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
        c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
        dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[0]), label, molabel, start=1)

        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
        log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **')
        dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[1]), label, molabel, start=1)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
Ejemplo n.º 36
0
    def __init__(self,
                 the_mf,
                 active_orbs,
                 localizationtype,
                 ao_rotation=None,
                 use_full_hessian=True,
                 localization_threshold=1e-6):

        assert ((localizationtype == 'meta_lowdin')
                or (localizationtype == 'boys')
                or (localizationtype == 'lowdin')
                or (localizationtype == 'iao'))

        # Information on the full SCF problem
        self.mo_occ = the_mf.mo_occ
        self.mol = the_mf.mol
        self.s1e_ao = the_mf.get_ovlp()
        self.fullEhf = the_mf.e_tot
        #self.fullDMao   = np.dot(np.dot( the_mf.mo_coeff, np.diag( the_mf.mo_occ )), the_mf.mo_coeff.T )
        self.fullDMao = the_mf.make_rdm1()
        #self.fullJKao   = scf.hf.get_veff( self.mol, self.fullDMao, 0, 0, 1 ) #Last 3 numbers: dm_last, vhf_last, hermi
        #self.fullJKao = the_mf.get_veff()
        #self.fullFOCKao = self.mol.intor_symmetric('int1e_kin') + self.mol.intor_symmetric('int1e_nuc') + self.fullJKao
        self.fullFOCKao = the_mf.get_fock()
        self.fullOEIao = the_mf.get_hcore()

        # Active space information
        self._which = localizationtype
        self.active = np.zeros([self.mol.nao_nr()], dtype=int)
        self.active[active_orbs] = 1
        self.NOrb = np.sum(self.active)  # Number of active space orbitals
        self.Nelec = int(
            np.rint(self.mol.nelectron -
                    np.sum(the_mf.mo_occ[self.active == 0]))
        )  # Total number of electrons minus frozen part

        # Localize the orbitals
        if ((self._which == 'meta_lowdin') or (self._which == 'boys')):
            if (self._which == 'meta_lowdin'):
                assert (self.NOrb == self.mol.nao_nr()
                        )  # Full active space required
            if (self._which == 'boys'):
                self.ao2loc = the_mf.mo_coeff[:, self.active == 1]
            if (self.NOrb == self.mol.nao_nr()
                ):  # If you want the full active, do meta-Lowdin
                nao.AOSHELL[4] = ['1s0p0d0f', '2s1p0d0f'
                                  ]  # redefine the valence shell for Be
                self.ao2loc = orth.orth_ao(self.mol, 'meta_lowdin')
                if (ao_rotation is not None):
                    self.ao2loc = np.dot(self.ao2loc, ao_rotation.T)
            if (self._which == 'boys'):
                old_verbose = self.mol.verbose
                self.mol.verbose = 5
                #loc = localizer.localizer( self.mol, self.ao2loc, self._which, use_full_hessian )
                boys = Boys(self.mol, self.ao2loc)
                self.mol.verbose = old_verbose
                #self.ao2loc = loc.optimize( threshold=localization_threshold )
                self.ao2loc = boys.kernel()
            self.TI_OK = False  # Check yourself if OK, then overwrite
        if (self._which == 'lowdin'):
            assert (self.NOrb == self.mol.nao_nr()
                    )  # Full active space required
            ovlp = self.mol.intor_symmetric('int1e_ovlp')
            ovlp_eigs, ovlp_vecs = np.linalg.eigh(ovlp)
            assert (np.linalg.norm(
                np.dot(np.dot(ovlp_vecs, np.diag(ovlp_eigs)), ovlp_vecs.T) -
                ovlp) < 1e-10)
            self.ao2loc = np.dot(
                np.dot(ovlp_vecs, np.diag(np.power(ovlp_eigs, -0.5))),
                ovlp_vecs.T)
            self.TI_OK = False  # Check yourself if OK, then overwrite
        if (self._which == 'iao'):
            assert (self.NOrb == self.mol.nao_nr()
                    )  # Full active space assumed
            self.ao2loc = iao_helper.localize_iao(self.mol, the_mf)
            if (ao_rotation is not None):
                self.ao2loc = np.dot(self.ao2loc, ao_rotation.T)
            self.TI_OK = False  # Check yourself if OK, then overwrite
            #self.molden( 'dump.molden' ) # Debugging mode
        assert (self.loc_ortho() < 1e-9)
        '''
        # Effective Hamiltonian due to frozen part
        self.frozenDMmo  = np.array( the_mf.mo_occ, copy=True )
        self.frozenDMmo[ self.active==1 ] = 0 # Only the frozen MO occupancies nonzero
        self.frozenDMao  = np.dot(np.dot( the_mf.mo_coeff, np.diag( self.frozenDMmo )), the_mf.mo_coeff.T )
        self.frozenJKao  = scf.hf.get_veff( self.mol, self.frozenDMao, 0, 0, 1 ) #Last 3 numbers: dm_last, vhf_last, hermi
        self.frozenOEIao = self.fullFOCKao - self.fullJKao + self.frozenJKao
        '''
        self.frozenOEIao = self.fullOEIao

        # Active space OEI and ERI
        self.activeCONST = self.mol.energy_nuc(
        )  #+ np.einsum( 'ij,ij->', self.frozenOEIao - 0.5*self.frozenJKao, self.frozenDMao )
        self.activeOEI = np.dot(np.dot(self.ao2loc.T, self.frozenOEIao),
                                self.ao2loc)
        self.activeFOCK = np.dot(np.dot(self.ao2loc.T, self.fullFOCKao),
                                 self.ao2loc)
        if (self.NOrb <= 150):
            self.ERIinMEM = True

            if (self.mol.cart):
                intor = 'int2e_cart'
            else:
                intor = 'int2e_sph'

            self.activeERI = ao2mo.outcore.full_iofree(
                self.mol, self.ao2loc, intor,
                compact=False).reshape(self.NOrb, self.NOrb, self.NOrb,
                                       self.NOrb)
        else:
            self.ERIinMEM = False
            self.activeERI = None
Ejemplo n.º 37
0
def analyze(casscf, mo_coeff=None, ci=None, verbose=logger.INFO,
            large_ci_tol=.1, **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    if mo_coeff is None: mo_coeff = casscf.mo_coeff
    if ci is None: ci = casscf.ci
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(casscf.stdout, verbose)
    nelecas = casscf.nelecas
    ncas = casscf.ncas
    ncore = casscf.ncore
    nocc = ncore + ncas
    label = casscf.mol.spheric_labels(True)

    if isinstance(ci, (tuple, list)):
        ci0 = ci[0]
        log.info('** Natural natural orbitals are based on the first root **')
    else:
        ci0 = ci
    if ci0 is None and hasattr(casscf, 'casdm1'):
        casdm1 = casscf.casdm1
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a
    elif hasattr(casscf.fcisolver, 'make_rdm1s'):
        casdm1a, casdm1b = casscf.fcisolver.make_rdm1s(ci0, ncas, nelecas)
        casdm1 = casdm1a + casdm1b
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1b = numpy.dot(mocore, mocore.T)
        dm1a = dm1b + reduce(numpy.dot, (mocas, casdm1a, mocas.T))
        dm1b += reduce(numpy.dot, (mocas, casdm1b, mocas.T))
        dm1 = dm1a + dm1b
        if log.verbose >= logger.DEBUG1:
            log.info('alpha density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1a, label, **kwargs)
            log.info('beta density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1b, label, **kwargs)
    else:
        casdm1 = casscf.fcisolver.make_rdm1(ci0, ncas, nelecas)
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a

    if log.verbose >= logger.INFO:
        ovlp_ao = casscf._scf.get_ovlp()
        # note the last two args of ._eig for mc1step_symm
        occ, ucas = casscf._eig(-casdm1, ncore, nocc)
        log.info('Natural occ %s', str(-occ))
        for i, k in enumerate(numpy.argmax(abs(ucas), axis=0)):
            if ucas[k,i] < 0:
                ucas[:,i] *= -1
        orth_coeff = orth.orth_ao(casscf.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff[:,ncore:nocc], ucas))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1, **kwargs)

        if casscf._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (casscf.mo_coeff.T, ovlp_ao, casscf._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<mo-mcscf|mo-hf> %d  %d  %12.8f', i+1, j+1, s[i,j])

        if hasattr(casscf.fcisolver, 'large_ci') and ci is not None:
            log.info('** Largest CI components **')
            if isinstance(ci, (tuple, list)):
                for i, civec in enumerate(ci):
                    res = casscf.fcisolver.large_ci(civec, casscf.ncas, casscf.nelecas)
                    log.info(' string alpha, string beta, state %d CI coefficient', i)
                    for c,ia,ib in res:
                        log.info('  %9s    %9s    %.12f', ia, ib, c)
            else:
                log.info(' string alpha, string beta, CI coefficient')
                res = casscf.fcisolver.large_ci(ci, casscf.ncas, casscf.nelecas)
                for c,ia,ib in res:
                    log.info('  %9s    %9s    %.12f', ia, ib, c)

        casscf._scf.mulliken_meta(casscf.mol, dm1, s=ovlp_ao, verbose=log)
    return dm1a, dm1b
Ejemplo n.º 38
0
def analyze(mf,
            verbose=logger.DEBUG,
            with_meta_lowdin=WITH_META_LOWDIN,
            **kwargs):
    '''Analyze the given SCF object:  print orbital energies, occupancies;
    print orbital coefficients; Mulliken population analysis; Dipole moment
    '''
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    nmo = len(mo_occ[0])
    log = logger.new_logger(mf, verbose)
    if log.verbose >= logger.NOTE:
        log.note('**** MO energy ****')
        log.note(
            '                             alpha | beta                alpha | beta'
        )
        for i in range(nmo):
            log.note('MO #%-3d energy= %-18.15g | %-18.15g occ= %g | %g',
                     i + MO_BASE, mo_energy[0][i], mo_energy[1][i],
                     mo_occ[0][i], mo_occ[1][i])

    ovlp_ao = mf.get_ovlp()
    if log.verbose >= logger.DEBUG:
        label = mf.mol.ao_labels()
        if with_meta_lowdin:
            log.debug(
                ' ** MO coefficients (expansion on meta-Lowdin AOs) for alpha spin **'
            )
            orth_coeff = orth.orth_ao(mf.mol, 'meta_lowdin', s=ovlp_ao)
            c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
            dump_mat.dump_rec(mf.stdout,
                              c_inv.dot(mo_coeff[0]),
                              label,
                              start=MO_BASE,
                              **kwargs)
            log.debug(
                ' ** MO coefficients (expansion on meta-Lowdin AOs) for beta spin **'
            )
            dump_mat.dump_rec(mf.stdout,
                              c_inv.dot(mo_coeff[1]),
                              label,
                              start=MO_BASE,
                              **kwargs)
        else:
            log.debug(
                ' ** MO coefficients (expansion on AOs) for alpha spin **')
            dump_mat.dump_rec(mf.stdout,
                              mo_coeff[0],
                              label,
                              start=MO_BASE,
                              **kwargs)
            log.debug(
                ' ** MO coefficients (expansion on AOs) for beta spin **')
            dump_mat.dump_rec(mf.stdout,
                              mo_coeff[1],
                              label,
                              start=MO_BASE,
                              **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    if with_meta_lowdin:
        return (mf.mulliken_meta(mf.mol, dm, s=ovlp_ao, verbose=log),
                mf.dip_moment(mf.mol, dm, verbose=log))
    else:
        return (mf.mulliken_pop(mf.mol, dm, s=ovlp_ao, verbose=log),
                mf.dip_moment(mf.mol, dm, verbose=log))
Ejemplo n.º 39
0
def analyze(mf, verbose=logger.DEBUG, **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    mol = mf.mol
    if not mol.symmetry:
        return uhf.analyze(mf, verbose, **kwargs)

    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    mo_coeff = mf.mo_coeff
    log = logger.Logger(mf.stdout, verbose)
    nirrep = len(mol.irrep_id)
    ovlp_ao = mf.get_ovlp()
    orbsyma = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb,
                                  mo_coeff[0], ovlp_ao, False)
    orbsymb = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb,
                                  mo_coeff[1], ovlp_ao, False)
    orbsyma = numpy.array(orbsyma)
    orbsymb = numpy.array(orbsymb)
    tot_sym = 0
    noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id]
    noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id]
    for i, ir in enumerate(mol.irrep_id):
        if (noccsa[i]+noccsb[i]) % 2:
            tot_sym ^= ir
    if mol.groupname in ('Dooh', 'Coov', 'SO3'):
        log.note('TODO: total symmetry for %s', mol.groupname)
    else:
        log.note('total symmetry = %s',
                 symm.irrep_id2name(mol.groupname, tot_sym))
    log.note('alpha occupancy for each irrep:  '+(' %4s'*nirrep),
             *mol.irrep_name)
    log.note('                                 '+(' %4d'*nirrep),
             *noccsa)
    log.note('beta  occupancy for each irrep:  '+(' %4s'*nirrep),
             *mol.irrep_name)
    log.note('                                 '+(' %4d'*nirrep),
             *noccsb)

    ss, s = mf.spin_square((mo_coeff[0][:,mo_occ[0]>0],
                            mo_coeff[1][:,mo_occ[1]>0]), ovlp_ao)
    log.note('multiplicity <S^2> = %.8g  2S+1 = %.8g', ss, s)

    if verbose >= logger.NOTE:
        log.note('**** MO energy ****')
        irname_full = {}
        for k, ir in enumerate(mol.irrep_id):
            irname_full[ir] = mol.irrep_name[k]
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+1, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k])
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            log.note('beta  MO #%d (%s #%d), energy= %.15g occ= %g',
                     k+1, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k])

    ovlp_ao = mf.get_ovlp()
    if mf.verbose >= logger.DEBUG:
        label = mol.spheric_labels(True)
        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsyma):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
        log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **')
        orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
        c_inv = numpy.dot(orth_coeff.T, ovlp_ao)
        dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[0]), label, molabel,
                          start=1, **kwargs)

        molabel = []
        irorbcnt = {}
        for k, j in enumerate(orbsymb):
            if j in irorbcnt:
                irorbcnt[j] += 1
            else:
                irorbcnt[j] = 1
            molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j]))
        log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **')
        dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[1]), label, molabel,
                          start=1, **kwargs)

    dm = mf.make_rdm1(mo_coeff, mo_occ)
    return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
Ejemplo n.º 40
0
def atomic_pops(mol, mo_coeff, method='meta_lowdin', mf=None):
    '''
    Kwargs:
        method : string
            The atomic population projection scheme. It can be mulliken,
            lowdin, meta_lowdin, iao, or becke

    Returns:
        A 3-index tensor [A,i,j] indicates the population of any orbital-pair
        density |i><j| for each species (atom in this case).  This tensor is
        used to construct the population and gradients etc.

        You can customize the PM localization wrt other population metric,
        such as the charge of a site, the charge of a fragment (a group of
        atoms) by overwriting this tensor.  See also the example
        pyscf/examples/loc_orb/40-hubbard_model_PM_localization.py for the PM
        localization of site-based population for hubbard model.
    '''
    method = method.lower().replace('_', '-')
    nmo = mo_coeff.shape[1]
    proj = numpy.empty((mol.natm, nmo, nmo))

    if getattr(mol, 'pbc_intor', None):  # whether mol object is a cell
        s = mol.pbc_intor('int1e_ovlp_sph', hermi=1)
    else:
        s = mol.intor_symmetric('int1e_ovlp')

    if method == 'becke':
        from pyscf.dft import gen_grid
        if not (getattr(mf, 'grids', None) and getattr(mf, '_numint', None)):
            # Call DFT to initialize grids and numint objects
            mf = mol.RKS()
        grids = mf.grids
        ni = mf._numint

        if not isinstance(grids, gen_grid.Grids):
            raise NotImplementedError('PM becke scheme for PBC systems')

        # The atom-wise Becke grids (without concatenated to a vector of grids)
        coords, weights = grids.get_partition(mol, concat=False)

        for i in range(mol.natm):
            ao = ni.eval_ao(mol, coords[i], deriv=0)
            aow = numpy.einsum('pi,p->pi', ao, weights[i])
            charge_matrix = lib.dot(aow.conj().T, ao)
            proj[i] = reduce(lib.dot,
                             (mo_coeff.conj().T, charge_matrix, mo_coeff))

    elif method == 'mulliken':
        for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()):
            csc = reduce(numpy.dot,
                         (mo_coeff[p0:p1].conj().T, s[p0:p1], mo_coeff))
            proj[i] = (csc + csc.conj().T) * .5

    elif method in ('lowdin', 'meta-lowdin'):
        c = orth.restore_ao_character(mol, 'ANO')
        #csc = reduce(lib.dot, (mo_coeff.conj().T, s, orth_local_ao_coeff))
        csc = reduce(lib.dot,
                     (mo_coeff.conj().T, s, orth.orth_ao(mol, method, c, s=s)))
        for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()):
            proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].conj().T)

    elif method in ('iao', 'ibo'):
        from pyscf.lo import iao
        assert mf is not None
        # FIXME: How to handle UHF/UKS object?
        orb_occ = mf.mo_coeff[:, mf.mo_occ > 0]

        iao_coeff = iao.iao(mol, orb_occ)
        #
        # IAO is generally not orthogonalized. For simplicity, we take Lowdin
        # orthogonalization here. Other orthogonalization can be used. Results
        # should be very closed to the Lowdin-orth orbitals
        #
        # PM with Mulliken population of non-orth IAOs can be found in
        # ibo.PipekMezey function
        #
        iao_coeff = orth.vec_lowdin(iao_coeff, s)
        csc = reduce(lib.dot, (mo_coeff.conj().T, s, iao_coeff))

        iao_mol = iao.reference_mol(mol)
        for i, (b0, b1, p0, p1) in enumerate(iao_mol.offset_nr_by_atom()):
            proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].conj().T)

    else:
        raise KeyError('method = %s' % method)

    return proj
Ejemplo n.º 41
0
    def analyze(self,
                verbose=None,
                with_meta_lowdin=WITH_META_LOWDIN,
                **kwargs):
        if verbose is None: verbose = self.verbose
        from pyscf.lo import orth
        from pyscf.tools import dump_mat
        if not self.mol.symmetry:
            return rohf.ROHF.analyze(self, verbose, with_meta_lowdin, **kwargs)

        mol = self.mol
        mo_energy = self.mo_energy
        mo_occ = self.mo_occ
        mo_coeff = self.mo_coeff
        ovlp_ao = self.get_ovlp()
        log = logger.new_logger(self, verbose)
        if log.verbose >= logger.NOTE:
            nirrep = len(mol.irrep_id)
            orbsym = get_orbsym(self.mol, mo_coeff)
            wfnsym = 0
            ndoccs = []
            nsoccs = []
            for k, ir in enumerate(mol.irrep_id):
                ndoccs.append(sum(orbsym[mo_occ == 2] == ir))
                nsoccs.append(sum(orbsym[mo_occ == 1] == ir))
                if nsoccs[k] % 2 == 1:
                    wfnsym ^= ir
            if mol.groupname in ('SO3', 'Dooh', 'Coov'):
                log.note('TODO: total wave-function symmetry for %s',
                         mol.groupname)
            else:
                log.note('Wave-function symmetry = %s',
                         symm.irrep_id2name(mol.groupname, wfnsym))
            log.note('occupancy for each irrep:  ' + (' %4s' * nirrep),
                     *mol.irrep_name)
            log.note('double occ                 ' + (' %4d' * nirrep),
                     *ndoccs)
            log.note('single occ                 ' + (' %4d' * nirrep),
                     *nsoccs)
            log.note('**** MO energy ****')
            irname_full = {}
            for k, ir in enumerate(mol.irrep_id):
                irname_full[ir] = mol.irrep_name[k]
            irorbcnt = {}
            if getattr(mo_energy, 'mo_ea', None) is not None:
                mo_ea = mo_energy.mo_ea
                mo_eb = mo_energy.mo_eb
                log.note(
                    '                          Roothaan           | alpha              | beta'
                )
                for k, j in enumerate(orbsym):
                    if j in irorbcnt:
                        irorbcnt[j] += 1
                    else:
                        irorbcnt[j] = 1
                    log.note(
                        'MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g',
                        k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k],
                        mo_ea[k], mo_eb[k], mo_occ[k])
            else:
                for k, j in enumerate(orbsym):
                    if j in irorbcnt:
                        irorbcnt[j] += 1
                    else:
                        irorbcnt[j] = 1
                    log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g',
                             k + MO_BASE, irname_full[j], irorbcnt[j],
                             mo_energy[k], mo_occ[k])

        if log.verbose >= logger.DEBUG:
            label = mol.ao_labels()
            molabel = []
            irorbcnt = {}
            for k, j in enumerate(orbsym):
                if j in irorbcnt:
                    irorbcnt[j] += 1
                else:
                    irorbcnt[j] = 1
                molabel.append('#%-d(%s #%d)' %
                               (k + MO_BASE, irname_full[j], irorbcnt[j]))
            if with_meta_lowdin:
                log.debug(
                    ' ** MO coefficients (expansion on meta-Lowdin AOs) **')
                orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao)
                c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff))
            else:
                log.debug(' ** MO coefficients (expansion on AOs) **')
                c = mo_coeff
            dump_mat.dump_rec(self.stdout,
                              c,
                              label,
                              molabel,
                              start=MO_BASE,
                              **kwargs)

        dm = self.make_rdm1(mo_coeff, mo_occ)
        if with_meta_lowdin:
            pop_and_charge = self.mulliken_meta(mol,
                                                dm,
                                                s=ovlp_ao,
                                                verbose=log)
        else:
            pop_and_charge = self.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log)
        dip = self.dip_moment(mol, dm, verbose=log)
        return pop_and_charge, dip
Ejemplo n.º 42
0
def analyze(casscf, mo_coeff=None, ci=None, verbose=logger.INFO,
            large_ci_tol=.1, **kwargs):
    from pyscf.lo import orth
    from pyscf.tools import dump_mat
    if mo_coeff is None: mo_coeff = casscf.mo_coeff
    if ci is None: ci = casscf.ci
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(casscf.stdout, verbose)
    nelecas = casscf.nelecas
    ncas = casscf.ncas
    ncore = casscf.ncore
    nocc = ncore + ncas
    label = casscf.mol.ao_labels()

    if isinstance(ci, (tuple, list)):
        ci0 = ci[0]
        log.info('** Natural natural orbitals are based on the first root **')
    else:
        ci0 = ci
    if ci0 is None and hasattr(casscf, 'casdm1'):
        casdm1 = casscf.casdm1
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a
    elif hasattr(casscf.fcisolver, 'make_rdm1s'):
        casdm1a, casdm1b = casscf.fcisolver.make_rdm1s(ci0, ncas, nelecas)
        casdm1 = casdm1a + casdm1b
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1b = numpy.dot(mocore, mocore.T)
        dm1a = dm1b + reduce(numpy.dot, (mocas, casdm1a, mocas.T))
        dm1b += reduce(numpy.dot, (mocas, casdm1b, mocas.T))
        dm1 = dm1a + dm1b
        if log.verbose >= logger.DEBUG1:
            log.info('alpha density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1a, label, **kwargs)
            log.info('beta density matrix (on AO)')
            dump_mat.dump_tri(log.stdout, dm1b, label, **kwargs)
    else:
        casdm1 = casscf.fcisolver.make_rdm1(ci0, ncas, nelecas)
        mocore = mo_coeff[:,:ncore]
        mocas = mo_coeff[:,ncore:nocc]
        dm1a =(numpy.dot(mocore, mocore.T) * 2
             + reduce(numpy.dot, (mocas, casdm1, mocas.T)))
        dm1b = None
        dm1 = dm1a

    if log.verbose >= logger.INFO:
        ovlp_ao = casscf._scf.get_ovlp()
        # note the last two args of ._eig for mc1step_symm
        occ, ucas = casscf._eig(-casdm1, ncore, nocc)
        log.info('Natural occ %s', str(-occ))
        for i, k in enumerate(numpy.argmax(abs(ucas), axis=0)):
            if ucas[k,i] < 0:
                ucas[:,i] *= -1
        orth_coeff = orth.orth_ao(casscf.mol, 'meta_lowdin', s=ovlp_ao)
        mo_cas = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff[:,ncore:nocc], ucas))
        log.info('Natural orbital (expansion on meta-Lowdin AOs) in CAS space')
        dump_mat.dump_rec(log.stdout, mo_cas, label, start=1, **kwargs)

        if casscf._scf.mo_coeff is not None:
            s = reduce(numpy.dot, (casscf.mo_coeff.T, ovlp_ao, casscf._scf.mo_coeff))
            idx = numpy.argwhere(abs(s)>.4)
            for i,j in idx:
                log.info('<mo-mcscf|mo-hf> %d  %d  %12.8f', i+1, j+1, s[i,j])

        if hasattr(casscf.fcisolver, 'large_ci') and ci is not None:
            log.info('** Largest CI components **')
            if isinstance(ci, (tuple, list)):
                for i, civec in enumerate(ci):
                    res = casscf.fcisolver.large_ci(civec, casscf.ncas, casscf.nelecas,
                                                    large_ci_tol, return_strs=False)
                    log.info('  [alpha occ-orbitals] [beta occ-orbitals]  state %-3d CI coefficient', i)
                    for c,ia,ib in res:
                        log.info('  %-20s %-30s %.12f', ia, ib, c)
            else:
                log.info('  [alpha occ-orbitals] [beta occ-orbitals]            CI coefficient')
                res = casscf.fcisolver.large_ci(ci, casscf.ncas, casscf.nelecas,
                                                large_ci_tol, return_strs=False)
                for c,ia,ib in res:
                    log.info('  %-20s %-30s %.12f', ia, ib, c)

        casscf._scf.mulliken_meta(casscf.mol, dm1, s=ovlp_ao, verbose=log)
    return dm1a, dm1b