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