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(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 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 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_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
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