示例#1
0
 def __init__(self, solver):
     # Solver is a pointer to a HF or a DFT calculation that has
     #  already converged
     self.solver = solver
     self.bfs = self.solver.bfs
     self.nbf = len(self.bfs)
     self.S = self.solver.S
     self.h = self.solver.h
     self.Ints = self.solver.Ints
     self.molecule = self.solver.molecule
     self.nel = self.molecule.get_nel()
     self.nclosed, self.nopen = self.molecule.get_closedopen()
     self.Enuke = self.molecule.get_enuke()
     self.norb = self.nbf
     self.orbs = self.solver.orbs
     self.orbe = self.solver.orbe
     self.Gij = []
     for g in xrange(self.nbf):
         gmat = zeros((self.nbf, self.nbf), 'd')
         self.Gij.append(gmat)
         gbf = self.bfs[g]
         for i in xrange(self.nbf):
             ibf = self.bfs[i]
             for j in xrange(i + 1):
                 jbf = self.bfs[j]
                 gij = three_center(ibf, gbf, jbf)
                 gmat[i, j] = gij
                 gmat[j, i] = gij
     D0 = mkdens(self.orbs, 0, self.nclosed)
     J0 = getJ(self.Ints, D0)
     Vfa = (2.0 * (self.nel - 1.0) / self.nel) * J0
     self.H0 = self.h + Vfa
     self.b = zeros(self.nbf, 'd')
     return
示例#2
0
文件: OEP.py 项目: certik/pyquante
 def __init__(self,solver):
     # Solver is a pointer to a HF or a DFT calculation that has
     #  already converged
     self.solver = solver
     self.bfs = self.solver.bfs
     self.nbf = len(self.bfs)
     self.S = self.solver.S
     self.h = self.solver.h
     self.Ints = self.solver.Ints
     self.molecule = self.solver.molecule
     self.nel = self.molecule.get_nel()
     self.nclosed, self.nopen = self.molecule.get_closedopen()
     self.Enuke = self.molecule.get_enuke()
     self.norb = self.nbf
     self.orbs = self.solver.orbs
     self.orbe = self.solver.orbe
     self.Gij = []
     for g in range(self.nbf):
         gmat = zeros((self.nbf,self.nbf),'d')
         self.Gij.append(gmat)
         gbf = self.bfs[g]
         for i in range(self.nbf):
             ibf = self.bfs[i]
             for j in range(i+1):
                 jbf = self.bfs[j]
                 gij = three_center(ibf,gbf,jbf)
                 gmat[i,j] = gij
                 gmat[j,i] = gij
     D0 = mkdens(self.orbs,0,self.nclosed)
     J0 = getJ(self.Ints,D0)
     Vfa = (2.0*(self.nel-1.0)/self.nel)*J0
     self.H0 = self.h + Vfa
     self.b = zeros(self.nbf,'d')
     return
示例#3
0
def SVD(S,bfs,U_gi):
	from PyQuante.CGBF import three_center
	"""
	Single variable decomposition (SVD) within HF product basis
	"""
	Sinv = linalg.inv(S)
	M = len(bfs)
	M2 = M**2
	ist,dict_ist = index_double(M)
	product_basis = zeros((M,M2),float)
	
	for a in range(M):
		for il, (i1,i2) in enumerate(ist):
			product_basis[a,il] = three_center(bfs[a],bfs[i1],bfs[i2])

	S_ijkl = dot(product_basis.T,dot(Sinv,product_basis))
	SHF_abcd = trans_4matrix(S_ijkl,U_gi)
	eivalSHF, eivecSHF = linalg.eigh(SHF_abcd)
	
	if False:
		test = matrix(eivecSHF.T)*matrix(eivecSHF)
		for ii in range(M*M):
			for jj in range(M*M):
				if ii==jj:
					if abs(1-test[ii,jj])>1e-6:
						print ii
				else: 
					if abs(test[ii,jj])>1e-6:
						print ii,jj
	for i,ev in enumerate(eivalSHF[::-1]):
		#print i,ev
		if ev < 1e-6:
			iLimit = i
			print 'iLimit of Tsvd = ',iLimit
			break
	
	Usvd = (eivecSHF.T[::-1][:iLimit]).T #Usvd_IP
	SQRTsigma = sqrt(eivalSHF[::-1][:iLimit])
	UdotS = dot(Usvd,diag(SQRTsigma)) #U_IP * sqrt(sigma_P)
	UdotSi = dot(Usvd,diag(1/SQRTsigma)) #U_IP * sqrt(1/sigma_P)
	#test = dot(U_inv_sqsigma.T,U_sqsigma)
	#print test
	return UdotS, UdotSi
示例#4
0
 def __init__(self, solver):
     # Solver is a pointer to a UHF calculation that has
     #  already converged
     self.solver = solver
     self.bfs = self.solver.bfs
     self.nbf = len(self.bfs)
     self.S = self.solver.S
     self.h = self.solver.h
     self.Ints = self.solver.Ints
     self.molecule = self.solver.molecule
     self.nel = self.molecule.get_nel()
     self.nalpha, self.nbeta = self.molecule.get_alphabeta()
     self.Enuke = self.molecule.get_enuke()
     self.norb = self.nbf
     self.orbsa = self.solver.orbsa
     self.orbsb = self.solver.orbsb
     self.orbea = self.solver.orbea
     self.orbeb = self.solver.orbeb
     self.Gij = []
     for g in xrange(self.nbf):
         gmat = zeros((self.nbf, self.nbf), 'd')
         self.Gij.append(gmat)
         gbf = self.bfs[g]
         for i in xrange(self.nbf):
             ibf = self.bfs[i]
             for j in xrange(i + 1):
                 jbf = self.bfs[j]
                 gij = three_center(ibf, gbf, jbf)
                 gmat[i, j] = gij
                 gmat[j, i] = gij
     D0 = mkdens(self.orbsa, 0, self.nalpha) + mkdens(
         self.orbsb, 0, self.nbeta)
     J0 = getJ(self.Ints, D0)
     Vfa = ((self.nel - 1.) / self.nel) * J0
     self.H0 = self.h + Vfa
     self.b = zeros(2 * self.nbf, 'd')
     return
示例#5
0
文件: OEP.py 项目: certik/pyquante
 def __init__(self,solver):
     # Solver is a pointer to a UHF calculation that has
     #  already converged
     self.solver = solver
     self.bfs = self.solver.bfs
     self.nbf = len(self.bfs)
     self.S = self.solver.S
     self.h = self.solver.h
     self.Ints = self.solver.Ints
     self.molecule = self.solver.molecule
     self.nel = self.molecule.get_nel()
     self.nalpha, self.nbeta = self.molecule.get_alphabeta()
     self.Enuke = self.molecule.get_enuke()
     self.norb = self.nbf
     self.orbsa = self.solver.orbsa
     self.orbsb = self.solver.orbsb
     self.orbea = self.solver.orbea
     self.orbeb = self.solver.orbeb
     self.Gij = []
     for g in range(self.nbf):
         gmat = zeros((self.nbf,self.nbf),'d')
         self.Gij.append(gmat)
         gbf = self.bfs[g]
         for i in range(self.nbf):
             ibf = self.bfs[i]
             for j in range(i+1):
                 jbf = self.bfs[j]
                 gij = three_center(ibf,gbf,jbf)
                 gmat[i,j] = gij
                 gmat[j,i] = gij
     D0 = mkdens(self.orbsa,0,self.nalpha)+mkdens(self.orbsb,0,self.nbeta)
     J0 = getJ(self.Ints,D0)
     Vfa = ((self.nel-1.)/self.nel)*J0
     self.H0 = self.h + Vfa
     self.b = zeros(2*self.nbf,'d')
     return
示例#6
0
文件: OEP.py 项目: certik/pyquante
def oep_uhf_an(atoms,orbsa,orbsb,**opts):
    """oep_hf - Form the optimized effective potential for HF exchange.

    Implementation of Wu and Yang's Approximate Newton Scheme
    from J. Theor. Comp. Chem. 2, 627 (2003).

    oep_uhf(atoms,orbs,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals

    Options
    -------
    bfs           None    The basis functions to use for the wfn
    pbfs          None    The basis functions to use for the pot
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    maxiter = opts.get('maxiter',100)
    tol = opts.get('tol',1e-5)
    ETemp = opts.get('ETemp',False)
    bfs = opts.get('bfs',None)
    if not bfs:
        basis = opts.get('basis',None)
        bfs = getbasis(atoms,basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs',None) 
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals',None)
    if integrals:
        S,h,Ints = integrals
    else:
        S,h,Ints = getints(bfs,atoms)

    nel = atoms.get_nel()
    nclosed,nopen = atoms.get_closedopen()
    nalpha,nbeta = nclosed+nopen,nclosed

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf

    ba = zeros(npbf,'d')
    bb = zeros(npbf,'d')

    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in range(npbf):
        gmat = zeros((nbf,nbf),'d')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in range(nbf):
            ibf = bfs[i]
            for j in range(i+1):
                jbf = bfs[j]
                gij = three_center(ibf,gbf,jbf)
                gmat[i,j] = gij
                gmat[j,i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix
    
    D0 = mkdens(orbsa,0,nalpha)+mkdens(orbsb,0,nbeta)
    J0 = getJ(Ints,D0)
    Vfa = ((nel-1.)/nel)*J0
    H0 = h + Vfa

    eold = 0

    for iter in range(maxiter):
        Hoepa = get_Hoep(ba,H0,Gij)
        Hoepb = get_Hoep(ba,H0,Gij)

        orbea,orbsa = geigh(Hoepa,S)
        orbeb,orbsb = geigh(Hoepb,S)

        if ETemp:
            efermia = get_efermi(2*nalpha,orbea,ETemp)
            occsa = get_fermi_occs(efermia,orbea,ETemp)
            Da = mkdens_occs(orbsa,occsa)
            efermib = get_efermi(2*nbeta,orbeb,ETemp)
            occsb = get_fermi_occs(efermib,orbeb,ETemp)
            Db = mkdens_occs(orbsb,occsb)
            entropy = 0.5*(get_entropy(occsa,ETemp)+get_entropy(occsb,ETemp))
        else:
            Da = mkdens(orbsa,0,nalpha)
            Db = mkdens(orbsb,0,nbeta)

        J = getJ(Ints,Da) + getJ(Ints,Db)
        Ka = getK(Ints,Da)
        Kb = getK(Ints,Db)

        energy = (trace2(2*h+J-Ka,Da)+trace2(2*h+J-Kb,Db))/2\
                 +Enuke
        if ETemp: energy += entropy
        
        if abs(energy-eold) < tol:
            break
        else:
            eold = energy
        
        logging.debug("OEP AN Opt: %d %f" % (iter,energy))

        # Do alpha and beta separately
        # Alphas
        dV_ao = J-Ka-Vfa
        dV = matrixmultiply(orbsa,matrixmultiply(dV_ao,transpose(orbsa)))
        X = zeros((nbf,nbf),'d')
        c = zeros(nbf,'d')
        for k in range(nbf):
            Gk = matrixmultiply(orbsa,matrixmultiply(Gij[k],
                                                    transpose(orbsa)))
            for i in range(nalpha):
                for a in range(nalpha,norb):
                    c[k] += dV[i,a]*Gk[i,a]/(orbea[i]-orbea[a])
            for l in range(nbf):
                Gl = matrixmultiply(orbsa,matrixmultiply(Gij[l],
                                                        transpose(orbsa)))
                for i in range(nalpha):
                    for a in range(nalpha,norb):
                        X[k,l] += Gk[i,a]*Gl[i,a]/(orbea[i]-orbea[a])
        # This should actually be a pseudoinverse...
        ba = solve(X,c)
        # Betas
        dV_ao = J-Kb-Vfa
        dV = matrixmultiply(orbsb,matrixmultiply(dV_ao,transpose(orbsb)))
        X = zeros((nbf,nbf),'d')
        c = zeros(nbf,'d')
        for k in range(nbf):
            Gk = matrixmultiply(orbsb,matrixmultiply(Gij[k],
                                                    transpose(orbsb)))
            for i in range(nbeta):
                for a in range(nbeta,norb):
                    c[k] += dV[i,a]*Gk[i,a]/(orbeb[i]-orbeb[a])
            for l in range(nbf):
                Gl = matrixmultiply(orbsb,matrixmultiply(Gij[l],
                                                        transpose(orbsb)))
                for i in range(nbeta):
                    for a in range(nbeta,norb):
                        X[k,l] += Gk[i,a]*Gl[i,a]/(orbeb[i]-orbeb[a])
        # This should actually be a pseudoinverse...
        bb = solve(X,c)

    logging.info("Final OEP energy = %f" % energy)
    return energy,(orbea,orbeb),(orbsa,orbsb)
示例#7
0
文件: OEP.py 项目: certik/pyquante
def oep_hf_an(atoms,orbs,**opts):
    """oep_hf - Form the optimized effective potential for HF exchange.

    Implementation of Wu and Yang's Approximate Newton Scheme
    from J. Theor. Comp. Chem. 2, 627 (2003).

    oep_hf(atoms,orbs,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals

    Options
    -------
    bfs           None    The basis functions to use for the wfn
    pbfs          None    The basis functions to use for the pot
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    maxiter = opts.get('maxiter',100)
    tol = opts.get('tol',1e-5)
    bfs = opts.get('bfs',None)
    if not bfs:
        basis = opts.get('basis',None)
        bfs = getbasis(atoms,basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs',None) 
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals',None)
    if integrals:
        S,h,Ints = integrals
    else:
        S,h,Ints = getints(bfs,atoms)

    nel = atoms.get_nel()
    nocc,nopen = atoms.get_closedopen()

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf
    bp = zeros(nbf,'d')

    bvec = opts.get('bvec',None)
    if bvec:
        assert len(bvec) == npbf
        b = array(bvec)
    else:
        b = zeros(npbf,'d')


    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in range(npbf):
        gmat = zeros((nbf,nbf),'d')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in range(nbf):
            ibf = bfs[i]
            for j in range(i+1):
                jbf = bfs[j]
                gij = three_center(ibf,gbf,jbf)
                gmat[i,j] = gij
                gmat[j,i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix
    
    D0 = mkdens(orbs,0,nocc)
    J0 = getJ(Ints,D0)
    Vfa = (2*(nel-1.)/nel)*J0
    H0 = h + Vfa

    b = zeros(nbf,'d')
    eold = 0

    for iter in range(maxiter):
        Hoep = get_Hoep(b,H0,Gij)
        orbe,orbs = geigh(Hoep,S)
        
        D = mkdens(orbs,0,nocc)
        Vhf = get2JmK(Ints,D)

        energy = trace2(2*h+Vhf,D)+Enuke
        if abs(energy-eold) < tol:
            break
        else:
            eold = energy
        
        logging.debug("OEP AN Opt: %d %f" % (iter,energy))
        dV_ao = Vhf-Vfa
        dV = matrixmultiply(transpose(orbs),matrixmultiply(dV_ao,orbs))

        X = zeros((nbf,nbf),'d')
        c = zeros(nbf,'d')
        Gkt = zeros((nbf,nbf),'d')

        for k in range(nbf):
            # This didn't work; in fact, it made things worse:
            Gk = matrixmultiply(transpose(orbs),matrixmultiply(Gij[k],orbs))
            for i in range(nocc):
                for a in range(nocc,norb):
                    c[k] += dV[i,a]*Gk[i,a]/(orbe[i]-orbe[a])
                    
            for l in range(nbf):
                Gl = matrixmultiply(transpose(orbs),matrixmultiply(Gij[l],orbs))
                for i in range(nocc):
                    for a in range(nocc,norb):
                        X[k,l] += Gk[i,a]*Gl[i,a]/(orbe[i]-orbe[a])
        # This should actually be a pseudoinverse...
        b = solve(X,c)

    logging.info("Final OEP energy = %f" % energy)
    return energy,orbe,orbs
示例#8
0
文件: OEP.py 项目: certik/pyquante
def oep(atoms,orbs,energy_func,grad_func=None,**opts):
    """oep - Form the optimized effective potential for a given energy expression

    oep(atoms,orbs,energy_func,grad_func=None,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals
    energy_func The function that returns the energy for the given method
    grad_func   The function that returns the force for the given method

    Options
    -------
    verbose       False   Output terse information to stdout (default)
                  True    Print out additional information 
    ETemp         False   Use ETemp value for finite temperature DFT (default)
                  float   Use (float) for the electron temperature
    bfs           None    The basis functions to use. List of CGBF's
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    verbose = opts.get('verbose',False)
    ETemp = opts.get('ETemp',False)
    opt_method = opts.get('opt_method','BFGS')

    bfs = opts.get('bfs',None)
    if not bfs:
        basis = opts.get('basis',None)
        bfs = getbasis(atoms,basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs',None) 
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals',None)
    if integrals:
        S,h,Ints = integrals
    else:
        S,h,Ints = getints(bfs,atoms)

    nel = atoms.get_nel()
    nocc,nopen = atoms.get_closedopen()

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf
    bp = zeros(nbf,'d')

    bvec = opts.get('bvec',None)
    if bvec:
        assert len(bvec) == npbf
        b = array(bvec)
    else:
        b = zeros(npbf,'d')

    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in range(npbf):
        gmat = zeros((nbf,nbf),'d')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in range(nbf):
            ibf = bfs[i]
            for j in range(i+1):
                jbf = bfs[j]
                gij = three_center(ibf,gbf,jbf)
                gmat[i,j] = gij
                gmat[j,i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix
    
    D0 = mkdens(orbs,0,nocc)
    J0 = getJ(Ints,D0)
    Vfa = (2*(nel-1.)/nel)*J0
    H0 = h + Vfa

    b = fminBFGS(energy_func,b,grad_func,
                 (nbf,nel,nocc,ETemp,Enuke,S,h,Ints,H0,Gij),
                 logger=logging)

    energy,orbe,orbs = energy_func(b,nbf,nel,nocc,ETemp,Enuke,
                                   S,h,Ints,H0,Gij,return_flag=1)
    return energy,orbe,orbs
示例#9
0
def oep_uhf_an(atoms, orbsa, orbsb, **opts):
    """oep_hf - Form the optimized effective potential for HF exchange.

    Implementation of Wu and Yang's Approximate Newton Scheme
    from J. Theor. Comp. Chem. 2, 627 (2003).

    oep_uhf(atoms,orbs,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals

    Options
    -------
    bfs           None    The basis functions to use for the wfn
    pbfs          None    The basis functions to use for the pot
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    maxiter = opts.get('maxiter', 100)
    tol = opts.get('tol', 1e-5)
    ETemp = opts.get('ETemp', False)
    bfs = opts.get('bfs', None)
    if not bfs:
        basis = opts.get('basis', None)
        bfs = getbasis(atoms, basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs', None)
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals', None)
    if integrals:
        S, h, Ints = integrals
    else:
        S, h, Ints = getints(bfs, atoms)

    nel = atoms.get_nel()
    nclosed, nopen = atoms.get_closedopen()
    nalpha, nbeta = nclosed + nopen, nclosed

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf

    ba = zeros(npbf, 'd')
    bb = zeros(npbf, 'd')

    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in xrange(npbf):
        gmat = zeros((nbf, nbf), 'd')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in xrange(nbf):
            ibf = bfs[i]
            for j in xrange(i + 1):
                jbf = bfs[j]
                gij = three_center(ibf, gbf, jbf)
                gmat[i, j] = gij
                gmat[j, i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix

    D0 = mkdens(orbsa, 0, nalpha) + mkdens(orbsb, 0, nbeta)
    J0 = getJ(Ints, D0)
    Vfa = ((nel - 1.) / nel) * J0
    H0 = h + Vfa

    eold = 0

    for iter in xrange(maxiter):
        Hoepa = get_Hoep(ba, H0, Gij)
        Hoepb = get_Hoep(ba, H0, Gij)

        orbea, orbsa = geigh(Hoepa, S)
        orbeb, orbsb = geigh(Hoepb, S)

        if ETemp:
            efermia = get_efermi(2 * nalpha, orbea, ETemp)
            occsa = get_fermi_occs(efermia, orbea, ETemp)
            Da = mkdens_occs(orbsa, occsa)
            efermib = get_efermi(2 * nbeta, orbeb, ETemp)
            occsb = get_fermi_occs(efermib, orbeb, ETemp)
            Db = mkdens_occs(orbsb, occsb)
            entropy = 0.5 * (get_entropy(occsa, ETemp) +
                             get_entropy(occsb, ETemp))
        else:
            Da = mkdens(orbsa, 0, nalpha)
            Db = mkdens(orbsb, 0, nbeta)

        J = getJ(Ints, Da) + getJ(Ints, Db)
        Ka = getK(Ints, Da)
        Kb = getK(Ints, Db)

        energy = (trace2(2*h+J-Ka,Da)+trace2(2*h+J-Kb,Db))/2\
                 +Enuke
        if ETemp: energy += entropy

        if abs(energy - eold) < tol:
            break
        else:
            eold = energy

        logging.debug("OEP AN Opt: %d %f" % (iter, energy))

        # Do alpha and beta separately
        # Alphas
        dV_ao = J - Ka - Vfa
        dV = matrixmultiply(orbsa, matrixmultiply(dV_ao, transpose(orbsa)))
        X = zeros((nbf, nbf), 'd')
        c = zeros(nbf, 'd')
        for k in xrange(nbf):
            Gk = matrixmultiply(orbsa, matrixmultiply(Gij[k],
                                                      transpose(orbsa)))
            for i in xrange(nalpha):
                for a in xrange(nalpha, norb):
                    c[k] += dV[i, a] * Gk[i, a] / (orbea[i] - orbea[a])
            for l in xrange(nbf):
                Gl = matrixmultiply(orbsa,
                                    matrixmultiply(Gij[l], transpose(orbsa)))
                for i in xrange(nalpha):
                    for a in xrange(nalpha, norb):
                        X[k, l] += Gk[i, a] * Gl[i, a] / (orbea[i] - orbea[a])
        # This should actually be a pseudoinverse...
        ba = solve(X, c)
        # Betas
        dV_ao = J - Kb - Vfa
        dV = matrixmultiply(orbsb, matrixmultiply(dV_ao, transpose(orbsb)))
        X = zeros((nbf, nbf), 'd')
        c = zeros(nbf, 'd')
        for k in xrange(nbf):
            Gk = matrixmultiply(orbsb, matrixmultiply(Gij[k],
                                                      transpose(orbsb)))
            for i in xrange(nbeta):
                for a in xrange(nbeta, norb):
                    c[k] += dV[i, a] * Gk[i, a] / (orbeb[i] - orbeb[a])
            for l in xrange(nbf):
                Gl = matrixmultiply(orbsb,
                                    matrixmultiply(Gij[l], transpose(orbsb)))
                for i in xrange(nbeta):
                    for a in xrange(nbeta, norb):
                        X[k, l] += Gk[i, a] * Gl[i, a] / (orbeb[i] - orbeb[a])
        # This should actually be a pseudoinverse...
        bb = solve(X, c)

    logger.info("Final OEP energy = %f" % energy)
    return energy, (orbea, orbeb), (orbsa, orbsb)
示例#10
0
def oep_hf_an(atoms, orbs, **opts):
    """oep_hf - Form the optimized effective potential for HF exchange.

    Implementation of Wu and Yang's Approximate Newton Scheme
    from J. Theor. Comp. Chem. 2, 627 (2003).

    oep_hf(atoms,orbs,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals

    Options
    -------
    bfs           None    The basis functions to use for the wfn
    pbfs          None    The basis functions to use for the pot
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    maxiter = opts.get('maxiter', 100)
    tol = opts.get('tol', 1e-5)
    bfs = opts.get('bfs', None)
    if not bfs:
        basis = opts.get('basis', None)
        bfs = getbasis(atoms, basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs', None)
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals', None)
    if integrals:
        S, h, Ints = integrals
    else:
        S, h, Ints = getints(bfs, atoms)

    nel = atoms.get_nel()
    nocc, nopen = atoms.get_closedopen()

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf
    bp = zeros(nbf, 'd')

    bvec = opts.get('bvec', None)
    if bvec:
        assert len(bvec) == npbf
        b = array(bvec)
    else:
        b = zeros(npbf, 'd')

    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in xrange(npbf):
        gmat = zeros((nbf, nbf), 'd')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in xrange(nbf):
            ibf = bfs[i]
            for j in xrange(i + 1):
                jbf = bfs[j]
                gij = three_center(ibf, gbf, jbf)
                gmat[i, j] = gij
                gmat[j, i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix

    D0 = mkdens(orbs, 0, nocc)
    J0 = getJ(Ints, D0)
    Vfa = (2 * (nel - 1.) / nel) * J0
    H0 = h + Vfa

    b = zeros(nbf, 'd')
    eold = 0

    for iter in xrange(maxiter):
        Hoep = get_Hoep(b, H0, Gij)
        orbe, orbs = geigh(Hoep, S)

        D = mkdens(orbs, 0, nocc)
        Vhf = get2JmK(Ints, D)

        energy = trace2(2 * h + Vhf, D) + Enuke
        if abs(energy - eold) < tol:
            break
        else:
            eold = energy

        logging.debug("OEP AN Opt: %d %f" % (iter, energy))
        dV_ao = Vhf - Vfa
        dV = matrixmultiply(transpose(orbs), matrixmultiply(dV_ao, orbs))

        X = zeros((nbf, nbf), 'd')
        c = zeros(nbf, 'd')
        Gkt = zeros((nbf, nbf), 'd')

        for k in xrange(nbf):
            # This didn't work; in fact, it made things worse:
            Gk = matrixmultiply(transpose(orbs), matrixmultiply(Gij[k], orbs))
            for i in xrange(nocc):
                for a in xrange(nocc, norb):
                    c[k] += dV[i, a] * Gk[i, a] / (orbe[i] - orbe[a])

            for l in xrange(nbf):
                Gl = matrixmultiply(transpose(orbs),
                                    matrixmultiply(Gij[l], orbs))
                for i in xrange(nocc):
                    for a in xrange(nocc, norb):
                        X[k, l] += Gk[i, a] * Gl[i, a] / (orbe[i] - orbe[a])
        # This should actually be a pseudoinverse...
        b = solve(X, c)

    logger.info("Final OEP energy = %f" % energy)
    return energy, orbe, orbs
示例#11
0
def oep(atoms, orbs, energy_func, grad_func=None, **opts):
    """oep - Form the optimized effective potential for a given energy expression

    oep(atoms,orbs,energy_func,grad_func=None,**opts)

    atoms       A Molecule object containing a list of the atoms
    orbs        A matrix of guess orbitals
    energy_func The function that returns the energy for the given method
    grad_func   The function that returns the force for the given method

    Options
    -------
    verbose       False   Output terse information to stdout (default)
                  True    Print out additional information 
    ETemp         False   Use ETemp value for finite temperature DFT (default)
                  float   Use (float) for the electron temperature
    bfs           None    The basis functions to use. List of CGBF's
    basis_data    None    The basis data to use to construct bfs
    integrals     None    The one- and two-electron integrals to use
                          If not None, S,h,Ints
    """
    verbose = opts.get('verbose', False)
    ETemp = opts.get('ETemp', False)
    opt_method = opts.get('opt_method', 'BFGS')

    bfs = opts.get('bfs', None)
    if not bfs:
        basis = opts.get('basis', None)
        bfs = getbasis(atoms, basis)

    # The basis set for the potential can be set different from
    #  that used for the wave function
    pbfs = opts.get('pbfs', None)
    if not pbfs: pbfs = bfs
    npbf = len(pbfs)

    integrals = opts.get('integrals', None)
    if integrals:
        S, h, Ints = integrals
    else:
        S, h, Ints = getints(bfs, atoms)

    nel = atoms.get_nel()
    nocc, nopen = atoms.get_closedopen()

    Enuke = atoms.get_enuke()

    # Form the OEP using Yang/Wu, PRL 89 143002 (2002)
    nbf = len(bfs)
    norb = nbf
    bp = zeros(nbf, 'd')

    bvec = opts.get('bvec', None)
    if bvec:
        assert len(bvec) == npbf
        b = array(bvec)
    else:
        b = zeros(npbf, 'd')

    # Form and store all of the three-center integrals
    # we're going to need.
    # These are <ibf|gbf|jbf> (where 'bf' indicates basis func,
    #                          as opposed to MO)
    # N^3 storage -- obviously you don't want to do this for
    #  very large systems
    Gij = []
    for g in xrange(npbf):
        gmat = zeros((nbf, nbf), 'd')
        Gij.append(gmat)
        gbf = pbfs[g]
        for i in xrange(nbf):
            ibf = bfs[i]
            for j in xrange(i + 1):
                jbf = bfs[j]
                gij = three_center(ibf, gbf, jbf)
                gmat[i, j] = gij
                gmat[j, i] = gij

    # Compute the Fermi-Amaldi potential based on the LDA density.
    # We're going to form this matrix from the Coulombic matrix that
    # arises from the input orbitals. D0 and J0 refer to the density
    # matrix and corresponding Coulomb matrix

    D0 = mkdens(orbs, 0, nocc)
    J0 = getJ(Ints, D0)
    Vfa = (2 * (nel - 1.) / nel) * J0
    H0 = h + Vfa

    b = fminBFGS(energy_func,
                 b,
                 grad_func,
                 (nbf, nel, nocc, ETemp, Enuke, S, h, Ints, H0, Gij),
                 logger=logging)

    energy, orbe, orbs = energy_func(b,
                                     nbf,
                                     nel,
                                     nocc,
                                     ETemp,
                                     Enuke,
                                     S,
                                     h,
                                     Ints,
                                     H0,
                                     Gij,
                                     return_flag=1)
    return energy, orbe, orbs