Beispiel #1
0
def hf1iter(molecule, psi, E, grid, T, pot_coulomb, eps, poisson_solver, num_iter=1):
    
    
    E_correct = molecule.energy
    
    eps_exchange = eps
    
    a = grid[0]
    b = grid[1]
    N = grid[2]
    
    h = (b-a)/(N-1)
    
    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i*h
    
    
    sf = h ** (3./2) # scaling factor
    
    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

    
    
    V = [0]*Norb
    psi_new = [0]*Norb


    prod = lambda A,B,C: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b, y0=C)
    
    
    
    for k in xrange(num_iter):

        
        density = tuck.zeros((N,N,N))  # density calculation
        for i in xrange(Norb):
            density = density + prod(tuck.conj(psi[i]), psi[i], psi[i]) # !can be faster!
            density = tuck.round(density, eps)
        pot_hartree = tuck.cross.conv(T, density, eps,pr=None)
        pot_hartree = tuck.round(tuck.real(pot_hartree),eps)

    
        E_electr = 0
        for i in xrange(Norb):
            V[i] =  prod(tuck.round(pot_coulomb + 2*pot_hartree, eps), psi[i], psi[i])
            exchange = qt.pots.exchange(psi, psi, i, eps_exchange, T, molecule)
            V[i] = tuck.round(V[i] - exchange, eps)
            
            # Full energy computation
            #V_energ = tuck.round(prod(2*pot_hartree, psi[i],psi[i]) - exchange, eps)
            #E_electr += 2*E[i] - sf**2*tuck.dot(psi[i], V_energ)
            
            psi_new[i] = -qt.poisson(2*V[i], -2*E[i], N, h, eps, solver=poisson_solver)
    

                
            #if abs( (E_full_1-E_full_0)/E_full_1 ) <= 3 * eps:
            #check += 1
                #if check == 3:
        #break

        
        ################# Fock matrix ###################
        
        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new)*sf**2) # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)
        
        # Fock matrix
        
        V_new = [0]*Norb
        for i in xrange(Norb):
            V_new[i] = prod(tuck.round(pot_coulomb + 2*pot_hartree,eps), psi_Q[i],psi_Q[i])
            exchange_new = qt.pots.exchange(psi_Q, psi, i, eps_exchange, T, molecule)
            V_new[i] = tuck.round(V_new[i] - exchange_new, eps)
    
    
    
        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new)*sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new)*sf**2 - np.dot(qt.bilinear(psi_Q, V)*sf**2, H(np.linalg.inv(L))) + Energ
        #F = np.real((F + F.T)/2)
        
        E_new = np.zeros(Norb, dtype = np.float64)
        E_new, S = np.linalg.eigh(F)
        
        
        
        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)
        
        E = E_new.copy()
        
        for i in xrange(Norb):
            if E[i]>0:
                E[i] = -0.0
    
    
    return psi, E
Beispiel #2
0
def lda(molecule, psi_0, E_0, grid, T, num_iter, eps, ind):

    pr = None

    E_correct = molecule.energy

    eps_exchange = eps

    a = grid[0]
    b = grid[1]
    N = grid[2]

    h = (b - a) / (N - 1)

    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i * h

    accuracy = np.zeros(num_iter)
    timing = np.zeros(num_iter)

    sf = h**(3. / 2)  # scaling factor

    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

    ##### Output #####
    output_E = np.zeros((Norb + 1, num_iter))
    output_r = np.zeros((3, num_iter))
    fname = molecule.name + '_' + 'lda' + '_' + str(N) + '_' + str(eps)

    ############################# Programm body ######################################

    psi = psi_0
    E = E_0
    V = [0] * Norb
    psi_new = [0] * Norb
    ################## Coulomb potential calculation ####################

    prod = lambda A, B, C: tuck.cross.multifun(
        [A, B], eps, lambda (a, b): a * b, y0=C)

    E_nuc = 0
    for i in xrange(num_atoms):
        vec_i = molecule.atoms[i].rad
        charge_i = molecule.atoms[i].charge
        for j in xrange(i):
            vec_j = molecule.atoms[j].rad
            charge_j = molecule.atoms[j].charge
            E_nuc = (E_nuc +
                     charge_i * charge_j / np.sqrt((vec_i[0] - vec_j[0])**2 +
                                                   (vec_i[1] - vec_j[1])**2 +
                                                   (vec_i[2] - vec_j[2])**2))

    print "Coulomb potential..."

    pot_coulomb = tuck.zeros((N, N, N))
    for i in xrange(num_atoms):
        vec = molecule.atoms[i].rad
        charge = molecule.atoms[i].charge
        pot_coulomb = pot_coulomb - charge * qt.pots.coulomb(x, vec, ind, eps)
        pot_coulomb = tuck.round(pot_coulomb, eps)

    ################## Iteration process ####################
    print "Iteration process..."

    time_hartree = 0
    time_exchange = 0
    time_other = 0
    time_whole = 0
    time_iter = 0

    check = 0

    E_full = 0
    E_full_0 = 0
    E_full_1 = 1

    for k in xrange(num_iter):
        print "############################################ "
        print "Iteration Number %s" % (k + 1)
        print "############################################ "

        time_hartree_iter = 0
        time_exchange_iter = 0
        start_iter = time.time()

        start_hartree_iter = time.time()
        density = tuck.zeros((N, N, N))  # density calculation
        for i in xrange(Norb):
            density = density + prod(tuck.conj(psi[i]), psi[i],
                                     psi[i])  # !can be faster!
            density = tuck.round(density, eps)
        density = 2 * density
        pot_hartree = tuck.cross.conv(T, density, eps, pr=None)
        pot_hartree = tuck.round(tuck.real(pot_hartree), eps)

        #density = tuck.real(density)
        #density = tuck.round(density , eps)
        end_hartree_iter = time.time()
        time_hartree_iter += (end_hartree_iter - start_hartree_iter)
        time_hartree += (end_hartree_iter - start_hartree_iter)

        E_electr = 0
        e_xc = tuck.cross.multifun([density, density],
                                   3 * eps,
                                   lambda (a, b):
                                   ((cen_fun(np.abs(np.real(a))) + xen_fun(
                                       np.abs(np.real(a)))) * np.abs(b)),
                                   y0=density,
                                   pr=pr)
        de_xc = tuck.cross.multifun(
            [density, density],
            3 * eps,
            lambda (a, b):
            ((cpot_fun(np.abs(np.real(a))) + xpot_fun(np.abs(np.real(a)))) *
             (b)),
            y0=density,
            pr=pr)
        e_h = 0.5 * prod(pot_hartree, density, density)

        E_h = sf**2 * tuck.dot(e_h, tuck.ones(e_xc.n))
        E_xc = sf**2 * tuck.dot(e_xc, tuck.ones(e_xc.n))
        dE_xc = sf**2 * tuck.dot(de_xc, tuck.ones(e_xc.n))
        #print E_xc, dE_xc, E_h

        for i in xrange(Norb):
            V[i] = prod(tuck.round(pot_coulomb + pot_hartree, eps), psi[i],
                        psi[i])
            psi[i] = tuck.real(psi[i])
            psi[i] = tuck.round(psi[i], eps)

        list = [None] * (Norb + 1)
        list[1:] = psi
        for i in xrange(Norb):
            list[0] = psi[i]
            Vxc = tuck.cross.multifun(
                list,
                10 * eps,
                lambda (a): ((cpot_fun(density_fun(a[1:])) + xpot_fun(
                    density_fun(a[1:]))) * (a[0])),
                y0=density,
                pr=pr
            )  # Somehow it can not converge if precision eps. That is why 3*eps is used
            V[i] = tuck.round(V[i] + Vxc, eps)

            # Full energy computation
            #V_energ = prod(pot_hartree, psi[i], psi[i])
            E_electr += 2 * E[
                i]  # - sf**2*tuck.dot(psi[i], V_energ)/2 #- sf**2*tuck.dot(e_xc, tuck.ones(Exc.n))

            psi_new[i] = -qt.poisson(2 * V[i], -2 * E[i], N, h, eps)

        E_full_0 = E_full
        E_full = E_electr - E_h + E_nuc + E_xc - dE_xc
        E_full_1 = E_full
        print 'Full Energy = %s' % (E_full)
        print 'Correct Energy = %s' % (E_correct)
        accuracy[k] = ((E_correct - E_full) / abs(E_correct))
        print 'Relative Precision of the full Energy = %s' % (accuracy[k])

        ################# Fock matrix ###################

        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new) *
                               sf**2)  # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)

        # Fock matrix

        V_new = [0] * Norb
        for i in xrange(Norb):
            V_new[i] = prod(tuck.round(pot_coulomb + pot_hartree, eps),
                            psi_Q[i], psi_Q[i])
            psi_Q[i] = tuck.real(psi_Q[i])
            psi_Q[i] = tuck.round(psi_Q[i], eps)

        list = [None] * (Norb + 1)
        list[1:] = psi_Q
        for i in xrange(Norb):
            list[0] = psi_Q[i]
            Vxc_new = tuck.cross.multifun(list,
                                          eps * 10,
                                          lambda (a):
                                          ((cpot_fun(density_fun(a[1:])) +
                                            xpot_fun(density_fun(a[1:]))) *
                                           (a[0])),
                                          y0=density,
                                          pr=pr)
            V_new[i] = tuck.round(V_new[i] + Vxc_new, eps)

        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new) * sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new) * sf**2 - np.dot(
            qt.bilinear(psi_Q, V) * sf**2, H(np.linalg.inv(L))) + Energ
        print 'Fock Matrix:'
        print F
        #F = np.real((F + F.T)/2)

        E_new = np.zeros(Norb, dtype=np.float64)
        E_new, S = np.linalg.eigh(F)

        output_E[:Norb, k] = E_new
        output_E[Norb, k] = E_full
        output_r[:, k] = density.r
        np.save('experiments/' + fname, [output_E[:, :k], output_r[:, :k]])

        print 'Orbital Energies:'
        print np.array(E_new)

        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)

        E = E_new.copy()

        for i in xrange(Norb):
            if E[i] > 0:
                E[i] = -0.0

        end_iter = time.time()
        print '1 Iteration Time: %s' % (end_iter - start_iter)
        print 'Hartree Time on this Iteration: %s' % (time_hartree_iter)
        #print 'Exchange Time on this Iteration: %s' % (time_exchange_iter)
        time_whole += (end_iter - start_iter)
        timing[k] = end_iter - start_iter

        if abs((E_full_1 - E_full_0) / E_full_1) <= 10 * eps:
            check += 1
            if check == 3:
                break

    print 'The Whole Time: %s' % (time_whole)
    return psi, E, accuracy, timing, E_full
Beispiel #3
0
def Hartree(molecule, psi_0, E_0, grid, T, num_iter, eps, ind):
    
    alpha = 0.0
    
    a = grid[0]
    b = grid[1]
    N = grid[2]
    
    h = (b-a)/(N-1)
    
    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i*h

    sf = h ** (3./2) # scaling factor

    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms
    
    
    ############################# Programm body ######################################
    
    psi = psi_0
    E = E_0
    V = [0]*Norb
    psi_new = [0]*Norb
    ################## Coulomb potential calculation ####################
            
    prod = lambda A,B: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b)
    
    print "Coulomb potential..."
    
    pot_coulomb = tuck.zeros((N,N,N))
    for i in xrange(num_atoms):
        vec = molecule.atoms[i].rad
        charge = molecule.atoms[i].charge
        pot_coulomb = pot_coulomb - charge * qt.pots.coulomb(x, vec, ind, eps)
        pot_coulomb = tuck.round(pot_coulomb, eps)

    ################## Iteration process ####################
    print "Iteration process..."

    for k in xrange(num_iter):
        
        density = tuck.zeros((N,N,N))  # density calculation
        for i in xrange(Norb):
            density = density + prod(tuck.conj(psi[i]), psi[i]) # !can be faster!
            density = tuck.round(density, eps)
        pot_hartree = tuck.cross.conv(T, density, eps)
        pot_hartree = tuck.round(tuck.real(pot_hartree),eps)

        for i in xrange(Norb):
            V[i] =  prod(tuck.round(pot_coulomb + pot_hartree, eps), psi[i])
            V[i] = tuck.round(V[i], eps)
            
            psi_new[i] = -qt.poisson(2*V[i], -2*E[i], N, h, eps)

        ################# Fock matrix ###################

        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new)*sf**2) # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)

        # Fock matrix

        V_new = [0]*Norb
        for i in xrange(Norb):
            V_new[i] =  prod(tuck.round(pot_coulomb + pot_hartree,eps), psi_Q[i])
            V_new[i] = tuck.round(V_new[i], eps)

        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new)*sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new)*sf**2 - np.dot(qt.bilinear(psi_Q, V)*sf**2, H(np.linalg.inv(L))) + Energ
        print F
        #F = np.real((F + F.T)/2)

        E_new = np.zeros(Norb, dtype = np.complex128)
        E_new, S = np.linalg.eigh(F)
        #E_new = alpha*E + (1-alpha)*E_new
        
        print np.array(E_new)
        
        psi_new = qt.prod(psi_Q, S.T, eps)
        for i in xrange(Norb):
            psi[i] = alpha*psi[i] + (1-alpha)*qt.normalize(psi_new[i], h)
            psi[i] = tuck.round(psi[i], eps)
        
        E = E_new.copy()
        
        for i in xrange(Norb):
            if E[i]>0:
                E[i] = -0.0    
    
    return E, psi
Beispiel #4
0
def lda(molecule,
        psi,
        E,
        density,
        grid,
        T,
        eps,
        pot_coulomb,
        max_iter=3,
        pr=None):

    E_correct = molecule.energy

    a = grid[0]
    b = grid[1]
    N = grid[2]

    h = (b - a) / (N - 1)

    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i * h

    accuracy = np.zeros(max_iter)
    timing = np.zeros(max_iter)

    sf = h**(3. / 2)  # scaling factor

    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

    ##### Output #####
    #output_E = np.zeros((Norb+1, max_iter))
    #output_r = np.zeros((3, max_iter))
    #fname = molecule.name + '_' + 'lda' + '_'  + str(N) + '_' + str(eps)

    ############################# Programm body ######################################

    V = [0] * Norb
    psi_new = [0] * Norb

    prod = lambda A, B, C: tuck.cross.multifun(
        [A, B], eps, lambda (a, b): a * b, y0=C)

    ################## Iteration process ####################

    pot_hartree = tuck.cross.conv(T, density, eps, y0=density, pr=None)
    pot_hartree = tuck.round(tuck.real(pot_hartree), eps)

    for k in xrange(max_iter):

        for i in xrange(Norb):
            V[i] = prod(tuck.round(pot_coulomb + pot_hartree, eps), psi[i],
                        psi[i])
            psi[i] = tuck.real(psi[i])
            psi[i] = tuck.round(psi[i], eps)

        for i in xrange(Norb):
            Vxc = tuck.cross.multifun([density, psi[i]],
                                      10 * eps,
                                      lambda (a, b):
                                      ((cpot_fun(np.abs(np.real(a))) +
                                        xpot_fun(np.abs(np.real(a)))) * (b)),
                                      y0=psi[i],
                                      pr=None)
            V[i] = tuck.round(V[i] + Vxc, eps)
            psi_new[i] = -qt.poisson(2 * V[i], -2 * E[i], N, h, eps)

        ################# Fock matrix ###################

        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new) *
                               sf**2)  # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)

        # Fock matrix

        V_new = [0] * Norb
        for i in xrange(Norb):
            V_new[i] = prod(tuck.round(pot_coulomb + pot_hartree, eps),
                            psi_Q[i], psi_Q[i])
            psi_Q[i] = tuck.real(psi_Q[i])
            psi_Q[i] = tuck.round(psi_Q[i], eps)

        for i in xrange(Norb):
            Vxc_new = tuck.cross.multifun([density, psi_Q[i]],
                                          10 * eps,
                                          lambda (a, b):
                                          ((cpot_fun(np.abs(np.real(a))) +
                                            xpot_fun(np.abs(np.real(a)))) *
                                           (b)),
                                          y0=psi_Q[i],
                                          pr=None)
            V_new[i] = tuck.round(V_new[i] + Vxc_new, eps)

        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new) * sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new) * sf**2 - np.dot(
            qt.bilinear(psi_Q, V) * sf**2, H(np.linalg.inv(L))) + Energ
        print 'Fock Matrix:'
        print F
        #F = np.real((F + F.T)/2)

        E_new = np.zeros(Norb, dtype=np.complex128)
        E_new, S = np.linalg.eigh(F)

        #output_E[:Norb,k] = E_new
        #output_E[Norb,k] = E_full
        #output_r[:,k] = density.r
        #np.save('experiments/' + fname, [output_E[:,:k], output_r[:,:k]])

        print 'Orbital Energies:'
        print np.array(E_new)

        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)

        if np.linalg.norm(E - E_new) / np.linalg.norm(E_new) < 2 * eps:
            break

        E = E_new.copy()

        for i in xrange(Norb):
            if E[i] > 0:
                E[i] = -0.0

    density = tuck.zeros((N, N, N))  # density calculation
    for i in xrange(Norb):
        density = density + prod(tuck.conj(psi[i]), psi[i],
                                 psi[i])  # !can be faster!
        density = tuck.round(density, eps)
    density = 2 * density

    return psi, E, density, F
Beispiel #5
0
def hf1iter(molecule,
            psi,
            E,
            grid,
            T,
            pot_coulomb,
            eps,
            poisson_solver,
            num_iter=1):

    E_correct = molecule.energy

    eps_exchange = eps

    a = grid[0]
    b = grid[1]
    N = grid[2]

    h = (b - a) / (N - 1)

    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i * h

    sf = h**(3. / 2)  # scaling factor

    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

    V = [0] * Norb
    psi_new = [0] * Norb

    prod = lambda A, B, C: tuck.cross.multifun(
        [A, B], eps, lambda (a, b): a * b, y0=C)

    for k in xrange(num_iter):

        density = tuck.zeros((N, N, N))  # density calculation
        for i in xrange(Norb):
            density = density + prod(tuck.conj(psi[i]), psi[i],
                                     psi[i])  # !can be faster!
            density = tuck.round(density, eps)
        pot_hartree = tuck.cross.conv(T, density, eps, pr=None)
        pot_hartree = tuck.round(tuck.real(pot_hartree), eps)

        E_electr = 0
        for i in xrange(Norb):
            V[i] = prod(tuck.round(pot_coulomb + 2 * pot_hartree, eps), psi[i],
                        psi[i])
            exchange = qt.pots.exchange(psi, psi, i, eps_exchange, T, molecule)
            V[i] = tuck.round(V[i] - exchange, eps)

            # Full energy computation
            #V_energ = tuck.round(prod(2*pot_hartree, psi[i],psi[i]) - exchange, eps)
            #E_electr += 2*E[i] - sf**2*tuck.dot(psi[i], V_energ)

            psi_new[i] = -qt.poisson(
                2 * V[i], -2 * E[i], N, h, eps, solver=poisson_solver)

            #if abs( (E_full_1-E_full_0)/E_full_1 ) <= 3 * eps:
            #check += 1
            #if check == 3:
        #break

        ################# Fock matrix ###################

        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new) *
                               sf**2)  # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)

        # Fock matrix

        V_new = [0] * Norb
        for i in xrange(Norb):
            V_new[i] = prod(tuck.round(pot_coulomb + 2 * pot_hartree, eps),
                            psi_Q[i], psi_Q[i])
            exchange_new = qt.pots.exchange(psi_Q, psi, i, eps_exchange, T,
                                            molecule)
            V_new[i] = tuck.round(V_new[i] - exchange_new, eps)

        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new) * sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new) * sf**2 - np.dot(
            qt.bilinear(psi_Q, V) * sf**2, H(np.linalg.inv(L))) + Energ
        #F = np.real((F + F.T)/2)

        E_new = np.zeros(Norb, dtype=np.float64)
        E_new, S = np.linalg.eigh(F)

        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)

        E = E_new.copy()

        for i in xrange(Norb):
            if E[i] > 0:
                E[i] = -0.0

    return psi, E
Beispiel #6
0
def lda_scf(solver, molecule, psi_0, E, grid, T, eps, pot_coulomb, pr=None, max_iter=1):
    
    E_correct = molecule.energy
    
    
    a = grid[0]
    b = grid[1]
    N = grid[2]
    
    h = (b-a)/(N-1)
    
    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i*h
    
    accuracy = np.zeros(max_iter)
    timing = np.zeros(max_iter)
    
    sf = h ** (3./2) # scaling factor
    
    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

            ##### Output #####
    #output_E = np.zeros((Norb+1, max_iter))
    #output_r = np.zeros((3, max_iter))
    #fname = molecule.name + '_' + 'lda' + '_'  + str(N) + '_' + str(eps)
    
    ############################# Programm body ######################################
    
    psi = psi_0
    V = [0]*Norb
    psi_new = [0]*Norb

    prod = lambda A,B,C: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b, y0=C, pr=pr)

    density = psi2dens(psi_0, eps)

    ################## Iteration process ####################
    
    pot_hartree = tuck.cross.conv(T, density, eps, y0=density, pr=pr)
    pot_hartree = tuck.round(tuck.real(pot_hartree), eps)
    pot_V = tuck.round(pot_coulomb + pot_hartree, eps)
    
    for k in xrange(max_iter):
    
        #print "1 scf iter", E
        
        for i in xrange(Norb):
            V[i] =  prod(pot_V, psi[i], psi[i])
            psi[i] = tuck.real(psi[i])
            psi[i] = tuck.round(psi[i], eps)
        

        for i in xrange(Norb):
            Vxc = tuck.cross.multifun(psi_0 + [psi[i]], 10*eps, lambda a: ((cpot_fun(density_fun(a[:-1])) + xpot_fun(density_fun(a[:-1])))*(a[-1])), y0 = psi[i], pr=pr)
            V[i] = tuck.round(V[i] + Vxc, eps)
            psi_new[i] = -qt.poisson(2*V[i], -2*E[i], N, h, eps)
    

                

        
        ################# Fock matrix ###################
        
        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new)*sf**2) # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)
        
        # Fock matrix
        
        V_new = [0]*Norb
        for i in xrange(Norb):
            V_new[i] = prod(pot_V, psi_Q[i], psi_Q[i])
            psi_Q[i] = tuck.real(psi_Q[i])
            psi_Q[i] = tuck.round(psi_Q[i], eps)
    
        for i in xrange(Norb):
            Vxc_new = tuck.cross.multifun(psi_0 + [psi_Q[i]], 10*eps, lambda a: ((cpot_fun(density_fun(a[:-1])) + xpot_fun(density_fun(a[:-1])))*(a[-1])), y0 = psi_Q[i], pr=pr)
            V_new[i] = tuck.round(V_new[i] + Vxc_new, eps)
    
        
        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new)*sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = ((qt.bilinear(psi_Q, V_new)*sf**2 - np.dot(qt.bilinear(psi_Q, V)*sf**2, H(np.linalg.inv(L))) + Energ ))
        #print 'Fock Matrix:'
        #print F
        #F = np.real((F + F.T)/2)
        
        #E_new = np.zeros(Norb, dtype = np.float64)
        E_new, S = np.linalg.eigh(F)
        #S+= 1e-15
        #output_E[:Norb,k] = E_new
        #output_E[Norb,k] = E_full
        #output_r[:,k] = density.r
        #np.save('experiments/' + fname, [output_E[:,:k], output_r[:,:k]])
        
        #print 'Orbital Energies:'
        #print np.array(E_new)

        #psi = copy.copy(psi_Q)
        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)
            
        #if np.linalg.norm(E - E_new)/np.linalg.norm(E_new) < 2*eps:
        #    break
        
        E = E_new.copy()
        

        for i in xrange(Norb):
            if E[i]>0:
                E[i] = -0.0
    

                    
    #density = tuck.zeros((N,N,N))  # density calculation
    #density = tuck.cross.multifun(psi, eps/10, lambda a: density_fun(a), y0 = psi_Q[i], pr=pr)

    return psi, E
Beispiel #7
0
def lda(molecule, psi_0, E_0, grid, T, num_iter, eps, ind):
    
    pr = None
    
    E_correct = molecule.energy
    
    eps_exchange = eps
    
    a = grid[0]
    b = grid[1]
    N = grid[2]
    
    h = (b-a)/(N-1)
    
    x = np.zeros(N)
    for i in xrange(N):
        x[i] = a + i*h
    
    accuracy = np.zeros(num_iter)
    timing = np.zeros(num_iter)
    
    sf = h ** (3./2) # scaling factor
    
    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

            ##### Output #####
    output_E = np.zeros((Norb+1, num_iter))
    output_r = np.zeros((3, num_iter))
    fname = molecule.name + '_' + 'lda' + '_'  + str(N) + '_' + str(eps)
    
    ############################# Programm body ######################################
    
    psi = psi_0
    E = E_0
    V = [0]*Norb
    psi_new = [0]*Norb
    ################## Coulomb potential calculation ####################

    prod = lambda A,B,C: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b, y0=C)
    
    E_nuc = 0
    for i in xrange(num_atoms):
        vec_i = molecule.atoms[i].rad
        charge_i = molecule.atoms[i].charge
        for j in xrange(i):
            vec_j = molecule.atoms[j].rad
            charge_j = molecule.atoms[j].charge
            E_nuc = (E_nuc + charge_i*charge_j/
                     np.sqrt((vec_i[0] - vec_j[0])**2 + (vec_i[1] - vec_j[1])**2 + (vec_i[2] - vec_j[2])**2))
    
    print "Coulomb potential..."
    
    pot_coulomb = tuck.zeros((N,N,N))
    for i in xrange(num_atoms):
        vec = molecule.atoms[i].rad
        charge = molecule.atoms[i].charge
        pot_coulomb = pot_coulomb - charge * qt.pots.coulomb(x, vec, ind, eps)
        pot_coulomb = tuck.round(pot_coulomb, eps)

    ################## Iteration process ####################
    print "Iteration process..."
    
    time_hartree = 0
    time_exchange = 0
    time_other = 0
    time_whole = 0
    time_iter = 0
    
    check = 0
    
    E_full = 0
    E_full_0 = 0
    E_full_1 = 1
    
    
    
    for k in xrange(num_iter):
        print "############################################ "
        print "Iteration Number %s" % (k + 1)
        print "############################################ "
        
        time_hartree_iter = 0
        time_exchange_iter = 0
        start_iter = time.time()
        
        start_hartree_iter = time.time()
        density = tuck.zeros((N,N,N))  # density calculation
        for i in xrange(Norb):
            density = density + prod(tuck.conj(psi[i]), psi[i], psi[i]) # !can be faster!
            density = tuck.round(density, eps)
        density = 2*density
        pot_hartree = tuck.cross.conv(T, density, eps,pr=None)
        pot_hartree = tuck.round(tuck.real(pot_hartree), eps)

    #density = tuck.real(density)
    #density = tuck.round(density , eps)
        end_hartree_iter = time.time()
        time_hartree_iter += (end_hartree_iter - start_hartree_iter)
        time_hartree += (end_hartree_iter - start_hartree_iter)

    
        E_electr = 0
        e_xc = tuck.cross.multifun([density, density], 3*eps, lambda (a, b): ((cen_fun(np.abs(np.real(a))) + xen_fun(np.abs(np.real(a))))*np.abs(b)), y0 = density, pr = pr)
        de_xc = tuck.cross.multifun([density, density],  3*eps, lambda (a, b): ((cpot_fun(np.abs(np.real(a))) + xpot_fun(np.abs(np.real(a))))*(b)), y0 = density, pr=pr)
        e_h = 0.5 * prod(pot_hartree, density, density)
        
        E_h = sf**2*tuck.dot(e_h, tuck.ones(e_xc.n))
        E_xc = sf**2*tuck.dot(e_xc, tuck.ones(e_xc.n))
        dE_xc = sf**2*tuck.dot(de_xc, tuck.ones(e_xc.n))
        #print E_xc, dE_xc, E_h
        
        
        for i in xrange(Norb):
            V[i] =  prod(tuck.round(pot_coulomb + pot_hartree, eps), psi[i], psi[i])
            psi[i] = tuck.real(psi[i])
            psi[i] = tuck.round(psi[i], eps)
        
        list = [None]*(Norb+1)
        list[1:] = psi
        for i in xrange(Norb):
            list[0] = psi[i]
            Vxc = tuck.cross.multifun(list, 10*eps, lambda (a): ((cpot_fun(density_fun(a[1:])) + xpot_fun(density_fun(a[1:])))*(a[0])), y0 = density, pr=pr) # Somehow it can not converge if precision eps. That is why 3*eps is used
            V[i] = tuck.round(V[i] + Vxc, eps)
            
            # Full energy computation
            #V_energ = prod(pot_hartree, psi[i], psi[i])
            E_electr += 2*E[i]# - sf**2*tuck.dot(psi[i], V_energ)/2 #- sf**2*tuck.dot(e_xc, tuck.ones(Exc.n))
            
            psi_new[i] = -qt.poisson(2*V[i], -2*E[i], N, h, eps)
    
        E_full_0 = E_full
        E_full = E_electr - E_h + E_nuc + E_xc - dE_xc
        E_full_1 = E_full
        print 'Full Energy = %s' % (E_full)
        print 'Correct Energy = %s' %(E_correct)
        accuracy[k] =  ((E_correct - E_full)/abs(E_correct))
        print 'Relative Precision of the full Energy = %s' % (accuracy[k])
                

        
        ################# Fock matrix ###################
        
        L = np.linalg.cholesky(qt.bilinear(psi_new, psi_new)*sf**2) # orthogonalization
        psi_Q = qt.UT_prod(psi_new, H(np.linalg.inv(L)), eps)
        
        # Fock matrix
        
        V_new = [0]*Norb
        for i in xrange(Norb):
            V_new[i] = prod(tuck.round(pot_coulomb + pot_hartree,eps), psi_Q[i], psi_Q[i])
            psi_Q[i] = tuck.real(psi_Q[i])
            psi_Q[i] = tuck.round(psi_Q[i], eps)
    
        list = [None]*(Norb+1)
        list[1:] = psi_Q
        for i in xrange(Norb):
            list[0] = psi_Q[i]
            Vxc_new = tuck.cross.multifun(list, eps*10, lambda (a): ((cpot_fun(density_fun(a[1:])) + xpot_fun(density_fun(a[1:])))*(a[0])), y0 = density, pr = pr)
            V_new[i] = tuck.round(V_new[i] + Vxc_new, eps)
    
    
        Energ1 = np.dot(np.diag(E), H(np.linalg.inv(L)))
        Energ2 = qt.bilinear(psi_new, psi_new)*sf**2
        Energ2 = np.dot(np.linalg.inv(L), Energ2)
        Energ = np.dot(Energ2, Energ1)
        F = qt.bilinear(psi_Q, V_new)*sf**2 - np.dot(qt.bilinear(psi_Q, V)*sf**2, H(np.linalg.inv(L))) + Energ
        print 'Fock Matrix:'
        print F
        #F = np.real((F + F.T)/2)
        
        E_new = np.zeros(Norb, dtype = np.float64)
        E_new, S = np.linalg.eigh(F)
        
        output_E[:Norb,k] = E_new
        output_E[Norb,k] = E_full
        output_r[:,k] = density.r
        np.save('experiments/'+fname, [output_E[:,:k], output_r[:,:k]])
        
        print 'Orbital Energies:'
        print np.array(E_new)
        
        psi = qt.prod(psi_Q, S.T, density, eps)
        for i in xrange(Norb):
            psi[i] = qt.normalize(psi[i], h)
            psi[i] = tuck.round(psi[i], eps)
        
        E = E_new.copy()
        
        for i in xrange(Norb):
            if E[i]>0:
                E[i] = -0.0
    
        end_iter = time.time()
        print '1 Iteration Time: %s' % (end_iter - start_iter)
        print 'Hartree Time on this Iteration: %s' % (time_hartree_iter)
                    #print 'Exchange Time on this Iteration: %s' % (time_exchange_iter)
        time_whole += (end_iter - start_iter)
        timing[k] = end_iter - start_iter
            
        if abs( (E_full_1-E_full_0)/E_full_1 ) <= 10 * eps:
            check += 1
            if check == 3:
                break

    print 'The Whole Time: %s' % (time_whole)                
    return psi, E, accuracy, timing, E_full