Example #1
0
def lda_full_energy(molecule, psi, E, pot_coulomb, grid, T, eps, ind, pr = None):
    
    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

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

    sf = h ** (3./2) # scaling factor
    
    
    Norb = molecule.orbitals
    num_atoms = molecule.num_atoms

    density = psi2dens(psi, eps)

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


    E_electr = 0
    e_xc = tuck.cross.multifun([density, density], 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],  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, dtype=np.float64))
    E_xc = sf**2*tuck.dot(e_xc, tuck.ones(e_xc.n, dtype=np.float64))
    dE_xc = sf**2*tuck.dot(de_xc, tuck.ones(e_xc.n, dtype=np.float64))
    #print E_xc, dE_xc, E_h
    
    

    for i in xrange(Norb):
        E_electr += 2*E[i]

    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))

    E_full = E_electr - E_h + E_nuc + E_xc - dE_xc

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

    return E_full
Example #2
0
def gaussian(x, gamma):  # Tucker representation of gaussian exp(-gamma * r**2)

    n = x.shape[0]
    a = tuck.ones((n, n, n))
    a.u[0][:, 0] = np.exp(-gamma * x**2)
    a.u[1][:, 0] = a.u[0][:, 0]
    a.u[2][:, 0] = a.u[0][:, 0]

    return a
Example #3
0
def gaussian(x, gamma): # Tucker representation of gaussian exp(-gamma * r**2)

    n = x.shape[0]
    a = tuck.ones((n, n, n))
    a.u[0][:,0] = np.exp(-gamma * x**2)
    a.u[1][:,0] = a.u[0][:,0]
    a.u[2][:,0] = a.u[0][:,0]

    return a
Example #4
0
def gradient_diatomic(self, smoothing=0.01):

        # pot squared
        #tensor_x = charge*tuck.round(vec[0]*tuck.ones((N, N, N)) - tensor_x, self.params.eps)
        #qt.pots.coulomb(x, vec, self.params.ind, self.params.eps, beta=3.0)
        #d_coulomb -= tuck.cross.multifun([tensor_x, pot_squared], self.params.eps, lambda x: x[0]*x[1])

        molecule = self.molecule
        x = self.params.grid
        h = x[1] - x[0]
        N = len(self.params.grid)
        Norb = self.molecule.orbitals
        num_atoms = self.molecule.num_atoms
        
        i = 0
        vec = molecule.atoms[i].rad
        charge = molecule.atoms[i].charge
        def fun_coulomb_squared((i, j, k)):
            r = np.sqrt((vec[0] - x[i])**2 + (vec[1] - x[j])**2 + (vec[2] - x[k])**2)
            return charge*(x[i] - vec[0]) / r * (-smoothed_coulomb_derivative(r/smoothing))/smoothing**2
        d_coulomb = tuck.cross.cross3d(fun_coulomb_squared, N, self.params.eps)
        d_coulomb = tuck.round(d_coulomb, self.params.eps)
        

        self.get_rho()
        
        dE_nuc = 0.0
        j = 1
        i = 0
        vec_i = molecule.atoms[i].rad
        charge_i = molecule.atoms[i].charge
        vec_j = molecule.atoms[j].rad
        charge_j = molecule.atoms[j].charge
        dE_nuc = (dE_nuc + (vec_i[0] - vec_j[0])*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)**3)


        return tuck.dot(d_coulomb, 2*tuck.ones(d_coulomb.n))*(x[1]-x[0])**3 #+ dE_nuc
Example #5
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
Example #6
0
# In[4]:


2*a - b


# In[16]:


x = sol.params.grid


# In[17]:


tuck.dot(sol.rho, tuck.ones(sol.rho.n))*(x[1]-x[0])**3


# In[4]:


from scipy.special import erf

def gradient_diatomic(self, smoothing=0.01):

        # pot squared
        #tensor_x = charge*tuck.round(vec[0]*tuck.ones((N, N, N)) - tensor_x, self.params.eps)
        #qt.pots.coulomb(x, vec, self.params.ind, self.params.eps, beta=3.0)
        #d_coulomb -= tuck.cross.multifun([tensor_x, pot_squared], self.params.eps, lambda x: x[0]*x[1])

        molecule = self.molecule
Example #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