def get_rho(self): self.rho = tuck.zeros(self.psi[0].n) for i in xrange(len(self.psi)): self.rho += tuck.cross.multifun([self.psi[i]], self.params.eps, lambda x: x[0]**2) self.rho = tuck.round(self.rho, self.params.eps)
def local(a,eps): b = tuck.zeros(a.n) b.n = a.n u1,v1,r1 = svd_trunc(a.u[0],eps) u2,v2,r2 = svd_trunc(a.u[1],eps) u3,v3,r3 = svd_trunc(a.u[2],eps) b.u[0] = u1 b.u[1] = u2 b.u[2] = u3 b.r = (r1,r2,r3) g = np.dot(a.core, np.transpose(v3)) g = np.transpose(g, [2,0,1]) g = np.dot(g, np.transpose(v2)) g = np.transpose(g, [0,2,1]) g = np.dot(g, np.transpose(v1)) b.core = np.transpose(g, [2,1,0]) return b
def LT_prod(psi, L, eps): #psi by L - Lower Triangular matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)] * Norb for i in xrange(Norb): for j in xrange(i + 1): psi_new[i] = psi_new[i] + L[i, j] * psi[j] psi_new[i] = tuck.round(psi_new[i], eps) return psi_new
def LT_prod(psi, L, eps): #psi by L - Lower Triangular matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)]*Norb for i in xrange(Norb): for j in xrange(i+1): psi_new[i] = psi_new[i] + L[i,j]*psi[j] psi_new[i] = tuck.round(psi_new[i], eps) return psi_new
def psi2dens(psi, eps): density = tuck.zeros(psi[0].n) for i in xrange(len(psi)): density = density + tuck.cross.multifun([psi[i]], eps/10, lambda a: a[0]**2, y0 = psi[i]) density = tuck.round(density, eps/10) density = 2*density return density
def psi2dens(psi, eps): density = tuck.zeros(psi[0].n) for i in xrange(len(psi)): density = density + tuck.cross.multifun([psi[i], psi[i]], eps/10, lambda (a,b): a*b, y0 = psi[i]) density = tuck.round(density, eps) density = 2*density return density
def UT_prod(psi, R, eps): #psi by R - Upper Triangular matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)]*Norb for i in xrange(Norb): for j in xrange(i+1): psi_new[i] = psi_new[i] + R[j,i]*psi[j] psi_new[i] = tuck.round(psi_new[i], eps) return psi_new
def UT_prod(psi, R, eps): #psi by R - Upper Triangular matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)] * Norb for i in xrange(Norb): for j in xrange(i + 1): psi_new[i] = psi_new[i] + R[j, i] * psi[j] psi_new[i] = tuck.round(psi_new[i], eps) return psi_new
def hf(molecule, psi, E, eps, grid, T, ind, max_iter, poisson_solver='Fourier'): 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 Norb = molecule.orbitals num_atoms = molecule.num_atoms 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) T0 = tuck.round(T, eps) k = 0 for i in xrange(max_iter): psi, E_new = hf1iter(molecule, psi, E, grid, T0, pot_coulomb, eps, poisson_solver) #print E if max(abs((E - E_new) / E)) < eps: k += 1 if k == 4: print 'Process converged with', i, 'iterations' break E = E_new print E if i == max_iter - 1: print 'Process did not converge with eps precision' E_full = hf_full_energy(molecule, psi, E, grid, tuck.round(T, eps * 1e-3), eps * 1e-3) print E_full return psi, E, E_full
def exchange(psi1, psi2, i, eps_exchange, T, molecule): exchange = tuck.zeros(psi1[0].n) for j in xrange(molecule.orbitals): conv = tuck.cross.multifun([psi1[i], psi2[j]], eps_exchange, lambda (a,b): a*b, y0 = psi1[i]) conv = tuck.cross.conv(T, conv, eps_exchange, y0 = conv) conv = tuck.round(tuck.real(conv),eps_exchange) conv = tuck.cross.multifun([psi2[j], conv], eps_exchange, lambda (a,b): a*b,y0 = psi2[j]) exchange = exchange + conv exchange = tuck.round(exchange, eps_exchange) return exchange
def get_coulomb(self): molecule = self.molecule x = self.params.grid N = len(self.params.grid) Norb = self.molecule.orbitals num_atoms = self.molecule.num_atoms 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, self.params.ind, self.params.eps) pot_coulomb = tuck.round(pot_coulomb, self.params.eps) self.pots.coulomb = pot_coulomb
def hf_full_energy(molecule, psi, E, grid, T, eps): eps_exchange = eps a = grid[0] b = grid[1] N = grid[2] h = (b - a) / (N - 1) sf = h**(3. / 2) Norb = molecule.orbitals num_atoms = molecule.num_atoms prod = lambda A, B, C: tuck.cross.multifun( [A, B], eps, lambda (a, b): a * b, y0=C) density = tuck.zeros((N, N, N)) # density calculation for i in xrange(Norb): density = density + prod(psi[i], psi[i], psi[i]) # !can be faster! density = tuck.round(density, eps) pot_hartree = tuck.cross.conv(T, density, eps) pot_hartree = tuck.real(pot_hartree) pot_hartree = tuck.round(pot_hartree, eps) V = [0] * Norb for i in xrange(Norb): V[i] = (prod(tuck.round(2 * pot_hartree, eps), psi[i], psi[i]) - qt.pots.exchange(psi, psi, i, eps_exchange, T, molecule)) V[i] = tuck.round(V[i], eps) E_electr = 0 for i in xrange(Norb): E_electr = E_electr + 2 * E[i] - sf**2 * tuck.dot(psi[i], V[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)) return E_nuc + E_electr
def hf_full_energy(molecule, psi, E, grid, T, eps): eps_exchange = eps a = grid[0] b = grid[1] N = grid[2] h = (b-a)/(N-1) sf = h ** (3./2) Norb = molecule.orbitals num_atoms = molecule.num_atoms prod = lambda A,B,C: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b, y0=C) density = tuck.zeros((N,N,N)) # density calculation for i in xrange(Norb): density = density + prod(psi[i], psi[i], psi[i]) # !can be faster! density = tuck.round(density, eps) pot_hartree = tuck.cross.conv(T, density, eps) pot_hartree = tuck.real(pot_hartree) pot_hartree = tuck.round(pot_hartree, eps) V = [0] * Norb for i in xrange(Norb): V[i] = (prod(tuck.round(2*pot_hartree, eps), psi[i], psi[i]) - qt.pots.exchange(psi, psi, i, eps_exchange, T, molecule)) V[i] = tuck.round(V[i], eps) E_electr = 0 for i in xrange(Norb): E_electr = E_electr + 2*E[i] - sf**2*tuck.dot(psi[i], V[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)) return E_nuc + E_electr
def get_coulomb(self): molecule = self.molecule x = self.params.grid N = len(self.params.grid) Norb = self.molecule.orbitals num_atoms = self.molecule.num_atoms 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, self.params.ind, self.params.eps) pot_coulomb = tuck.round(pot_coulomb, self.params.eps) self.pots.coulomb = pot_coulomb
def prod(psi, S, density, eps): #psi by S matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)] * Norb for i in xrange(Norb): for j in xrange(Norb): psi_new[i] = psi_new[i] + S[i, j] * psi[j] psi_new[i] = tuck.round(psi_new[i], eps) #def psi_S_i(psi): # res = 0. # for j in xrange(Norb): # res += (S[i, j]) * psi[j] # return np.real(res) #psi_new[i] = tuck.cross.multifun(psi, eps, lambda a: psi_S_i(a), y0 = density, pr = 1) return psi_new
def prod(psi, S, density, eps): #psi by S matrix multiplication Norb = len(psi) psi_new = [tuck.zeros(psi[0].n)]*Norb for i in xrange(Norb): for j in xrange(Norb): psi_new[i] = psi_new[i] + S[i,j]*psi[j] psi_new[i] = tuck.round(psi_new[i], eps) #def psi_S_i(psi): # res = 0. # for j in xrange(Norb): # res += (S[i, j]) * psi[j] # return np.real(res) #psi_new[i] = tuck.cross.multifun(psi, eps, lambda a: psi_S_i(a), y0 = density, pr = 1) return psi_new
def exchange(psi1, psi2, i, eps_exchange, T, molecule): exchange = tuck.zeros(psi1[0].n) for j in xrange(molecule.orbitals): conv = tuck.cross.multifun([psi1[i], psi2[j]], eps_exchange, lambda (a, b): a * b, y0=psi1[i]) conv = tuck.cross.conv(T, conv, eps_exchange, y0=conv) conv = tuck.round(tuck.real(conv), eps_exchange) conv = tuck.cross.multifun([psi2[j], conv], eps_exchange, lambda (a, b): a * b, y0=psi2[j]) exchange = exchange + conv exchange = tuck.round(exchange, eps_exchange) return exchange
def hf(molecule, psi, E, eps, grid, T, ind, max_iter, poisson_solver='Fourier'): 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 Norb = molecule.orbitals num_atoms = molecule.num_atoms 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) T0 = tuck.round(T, eps) k=0 for i in xrange(max_iter): psi, E_new = hf1iter(molecule, psi, E, grid, T0, pot_coulomb, eps, poisson_solver) #print E if max(abs((E-E_new)/E))<eps: k += 1 if k == 4: print 'Process converged with', i, 'iterations' break E = E_new print E if i == max_iter - 1: print 'Process did not converge with eps precision' E_full = hf_full_energy(molecule, psi, E, grid, tuck.round(T, eps*1e-3), eps*1e-3) print E_full return psi, E, E_full
def local(a, eps): b = tuck.zeros(a.n, dtype=np.float64) b.n = a.n u1, v1, r1 = svd_trunc(a.u[0], eps) u2, v2, r2 = svd_trunc(a.u[1], eps) u3, v3, r3 = svd_trunc(a.u[2], eps) b.u[0] = np.real(u1) b.u[1] = np.real(u2) b.u[2] = np.real(u3) b.r = (r1, r2, r3) g = np.dot(a.core, np.transpose(v3)) g = np.transpose(g, [2, 0, 1]) g = np.dot(g, np.transpose(v2)) g = np.transpose(g, [0, 2, 1]) g = np.dot(g, np.transpose(v1)) b.core = np.real(np.transpose(g, [2, 1, 0])) return b
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
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
def lda_full_energy(molecule, psi, E, density, grid, T, eps, 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 accuracy = np.zeros(max_iter) timing = np.zeros(max_iter) sf = h**(3. / 2) # scaling factor prod = lambda A, B: tuck.cross.multifun([A, B], eps, lambda (a, b): a * b) Norb = molecule.orbitals num_atoms = molecule.num_atoms density = tuck.zeros((N, N, N)) # density calculation for i in xrange(Norb): density = density + prod(psi[i], psi[i], psi[i]) # !can be faster! density = tuck.round(density, eps) pot_hartree = tuck.cross.conv(T, density, 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)) 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) 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) #accuracy[k] = ((E_correct - E_full)/abs(E_correct)) #print 'Relative Precision of the full Energy = %s' % (accuracy[k]) return E_full
def lda_full_energy(molecule, psi, E, density, 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 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) 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_h + E_nuc + E_xc - dE_xc print 'Full Energy = %s' % (E_full) #accuracy[k] = ((E_correct - E_full)/abs(E_correct)) #print 'Relative Precision of the full Energy = %s' % (accuracy[k]) return E_full
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
def mixing(solver, molecule, psi_0, E_0, eps, grid, T, ind, max_iter, m, max_iter_inscf, pr): count = 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 Norb = molecule.orbitals num_atoms = molecule.num_atoms 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) G = lambda psi, E, rho: solvers.dft_dens.lda(molecule, psi, E, rho, grid, T, eps, pot_coulomb, max_iter=max_iter_inscf, pr=pr)[0:4] Norb = molecule.orbitals rho = psi2dens(psi_0, eps) rho_m = [] Grho_m = [] D_m = [] rho_m.append(rho) res = G(psi_0, E_0, rho) psi = res[0] E = res[1] Grho_m.append(res[2]) D_m.append(tuck.round(Grho_m[0] - rho, eps)) rho = Grho_m[0] err_and = np.zeros(max_iter) for k in xrange(1, max_iter): mk = min(k, m) f = np.zeros(mk + 1) f[mk] = 1. A = np.ones((mk + 1, mk + 1)) A[mk, mk] = 0. for p in xrange(mk): for q in xrange(mk): A[p, q] += 2 * qt.inner(D_m[p], D_m[q], h) alpha = np.linalg.pinv(A).dot(f) #alpha = np.array([0.5, 0.5, 1.]) if len(alpha) == 3: if alpha[0] > 1. + 1e-2: alpha[0] = .1 alpha[1] = .9 if alpha[0] < 0. - 1e-2: alpha[0] = 0.1 alpha[1] = .9 rho_temp = tuck.zeros((N, N, N)) for p in xrange(mk): rho_temp += tuck.round(alpha[p] * Grho_m[p], eps / 10) rho = tuck.round(rho_temp, eps / 10) #print alpha rho_m.append(rho) rho_m = rho_m[-min(k + 1, m):] res = G(psi, E, rho) psi = res[0] E_new = res[1] err_and[k] = max(np.abs(E - E_new) / np.abs(E_new)) #if err_and[k] < eps: #break solver.psi = psi solver.orb_energies = E_new print solver.psi[0].r, solver.psi[-1].r print E_new err = abs((E - E_new) / E) E = copy.copy(E_new) #solver.iterative.orb_energies.append(E_new) #solver.iterative.convergence.append(err) print 'Iteration', k, 'accuracy = %.2e' % max(err) if max(err) < 4 * eps: count += 1 if count == 4: print 'Process converged with', i, 'iterations' break Grho_m.append(res[2]) Grho_m = Grho_m[-min(k + 1, m):] D_m.append(tuck.round(Grho_m[-1] - rho_m[-1], eps)) D_m = D_m[-min(k + 1, m):] Eel = solvers.dft_dens.lda(molecule, psi, E, rho, grid, T, eps * 1e-2, pot_coulomb, max_iter=max_iter_inscf, pr=pr)[1] Efull = solvers.dft_dens.lda_full_energy( molecule, psi, E, rho, grid, T, eps * 1e-2, ind, pr=None) + 2 * np.sum(Eel) print Efull solver.energy = Efull return psi, E, rho, Efull, err_and
def mixing(solver, molecule, psi_0, E_0, eps, grid, T, ind, max_iter, m, max_iter_inscf, pr): count = 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 Norb = molecule.orbitals num_atoms = molecule.num_atoms 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) G = lambda psi, E, rho: solvers.dft_dens.lda(molecule, psi, E, rho, grid, T, eps, pot_coulomb, max_iter = max_iter_inscf, pr=pr)[0:4] Norb = molecule.orbitals rho = psi2dens(psi_0, eps) rho_m = [] Grho_m = [] D_m = [] rho_m.append(rho) res = G(psi_0, E_0, rho) psi = res[0] E = res[1] Grho_m.append(res[2]) D_m.append(tuck.round(Grho_m[0] - rho, eps)) rho = Grho_m[0] err_and = np.zeros(max_iter) for k in xrange(1, max_iter): mk = min(k, m) f = np.zeros(mk + 1) f[mk] = 1. A = np.ones((mk + 1, mk + 1)) A[mk, mk] = 0. for p in xrange(mk): for q in xrange(mk): A[p, q] += 2 * qt.inner(D_m[p], D_m[q], h) alpha = np.linalg.pinv(A).dot(f) #alpha = np.array([0.5, 0.5, 1.]) if len(alpha) == 3: if alpha[0]> 1. + 1e-2: alpha[0] = .1 alpha[1] = .9 if alpha[0]< 0. - 1e-2: alpha[0] = 0.1 alpha[1] = .9 rho_temp = tuck.zeros((N, N, N)) for p in xrange(mk): rho_temp += tuck.round(alpha[p] * Grho_m[p], eps/10) rho = tuck.round(rho_temp, eps/10) #print alpha rho_m.append(rho) rho_m = rho_m[-min(k + 1, m):] res = G(psi, E, rho) psi = res[0] E_new = res[1] err_and[k] = max(np.abs(E - E_new)/np.abs(E_new)) #if err_and[k] < eps: #break solver.psi = psi solver.orb_energies = E_new print solver.psi[0].r, solver.psi[-1].r print E_new err = abs((E-E_new)/E) E = copy.copy(E_new) #solver.iterative.orb_energies.append(E_new) #solver.iterative.convergence.append(err) print 'Iteration', k, 'accuracy = %.2e' % max(err) if max(err) < 4 * eps: count += 1 if count == 4: print 'Process converged with', i, 'iterations' break Grho_m.append(res[2]) Grho_m = Grho_m[-min(k + 1, m):] D_m.append(tuck.round(Grho_m[-1] - rho_m[-1], eps)) D_m = D_m[-min(k + 1, m):] Eel = solvers.dft_dens.lda(molecule, psi, E, rho, grid, T, eps*1e-2, pot_coulomb, max_iter = max_iter_inscf, pr=pr)[1] Efull = solvers.dft_dens.lda_full_energy(molecule, psi, E, rho, grid, T, eps*1e-2, ind, pr = None) + 2*np.sum(Eel) print Efull solver.energy = Efull return psi, E, rho, Efull, err_and
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
def lda_full_energy(molecule, psi, E, density, 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 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) 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_h + E_nuc + E_xc - dE_xc print 'Full Energy = %s' % (E_full) #accuracy[k] = ((E_correct - E_full)/abs(E_correct)) #print 'Relative Precision of the full Energy = %s' % (accuracy[k]) return E_full
def lda(molecule, psi_0, E, density, grid, T, eps, pot_coulomb, pr = None, max_iter = 3): 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) ################## 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]], 5*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]], 5*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, density, F
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
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