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_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 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 pyquante_hf(mol, x, eps, basis = "sto-3g"): atoms = [None]*mol.num_atoms for i in xrange(mol.num_atoms): atoms[i] = (mol.atoms[i].charge, (mol.atoms[i].rad[0],mol.atoms[i].rad[1],mol.atoms[i].rad[2])) mol_pq = Molecule(mol.name, atoms, units='Bohr') solver = SCF(mol_pq,method="HF",ConvCriteria=1e-7,MaxIter=40,basis=basis) print 'SCF iteration - done' solver.iterate() norb=int(solver.solver.nclosed) w=solver.basis_set.get() cf=solver.solver.orbs[:,0:norb] psi = [None]*norb for i in xrange(norb): psi[i] = gto2tuck(w,cf[:,i],x) print psi[i].r psi[i] = local(psi[i],1e-14) psi[i] = tuck.round(psi[i],eps) print psi[i].r E = solver.solver.orbe[:norb] return psi,E
def lda_full_energy(molecule, psi, E, grid, T, eps, eps_exchange): 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: tuck.cross.multifun([A,B], eps, lambda (a,b): a*b) 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) 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 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 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 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 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 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], psi[i]], eps/10, lambda (a,b): a*b, y0 = psi[i]) density = tuck.round(density, eps) density = 2*density return density
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 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 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 newton_galerkin(x, eps, ind): # galerkin tensor for convolution as a hartree potential if ind == 6: a, b, r = -15., 10, 80 elif ind == 8: a, b, r = -20., 15, 145 elif ind == 10: a, b, r = -25., 20, 220 elif ind == 12: a, b, r = -30., 25, 320 else: raise Exception("wrong ind parameter") N = x.shape hr = (b-a)/(r - 1) h = x[1]-x[0] s = np.array(range(r), dtype = np.complex128) s = a + hr * (s - 1) w = np.zeros(r, dtype = np.complex128) for alpha in xrange(r): w[alpha] = 2*hr * np.exp(s[alpha]) / np.sqrt(pi) w[0] = w[0]/2 w[r-1] = w[r-1]/2 U = np.zeros((N[0], r), dtype = np.complex128) for alpha in xrange(r): U[:, alpha] = ( func_int(x-h/2, x[0]-h/2, np.exp(2*s[alpha])) - func_int(x+h/2, x[0]-h/2, np.exp(2*s[alpha])) + func_int(x+h/2, x[0]+h/2, np.exp(2*s[alpha])) - func_int(x-h/2, x[0]+h/2, np.exp(2*s[alpha])) ) newton = can2tuck(w, U, U, U) newton = tuck.round(newton, eps) return (1./h**3) * newton
def newton_galerkin(x, eps, ind): # galerkin tensor for convolution as a hartree potential if ind == 6: a, b, r = -15., 10, 80 elif ind == 8: a, b, r = -20., 15, 145 elif ind == 10: a, b, r = -25., 20, 220 elif ind == 12: a, b, r = -30., 25, 320 else: raise Exception("wrong ind parameter") N = x.shape hr = (b - a) / (r - 1) h = x[1] - x[0] s = np.array(range(r), dtype=np.complex128) s = a + hr * (s - 1) w = np.zeros(r, dtype=np.complex128) for alpha in xrange(r): w[alpha] = 2 * hr * np.exp(s[alpha]) / np.sqrt(pi) w[0] = w[0] / 2 w[r - 1] = w[r - 1] / 2 U = np.zeros((N[0], r), dtype=np.complex128) for alpha in xrange(r): U[:, alpha] = (func_int(x - h / 2, x[0] - h / 2, np.exp(2 * s[alpha])) - func_int(x + h / 2, x[0] - h / 2, np.exp(2 * s[alpha])) + func_int(x + h / 2, x[0] + h / 2, np.exp(2 * s[alpha])) - func_int(x - h / 2, x[0] + h / 2, np.exp(2 * s[alpha]))) newton = can2tuck(w, U, U, U) newton = tuck.round(newton, eps) return (1. / h**3) * newton
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 * self.rho) * (x[1] - x[0])**3 + dE_nuc
def coulomb(x, vec, ind, eps, beta=1.0): # 1/|r-vec|**beta in Tucker format if ind == 6: a, b, r = -15., 10, 80 elif ind == 8: a, b, r = -20., 15, 145 elif ind == 10: a, b, r = -25., 20, 220 elif ind == 12: a, b, r = -30., 25, 320 else: raise Exception("wrong ind parameter") N = x.shape h = (b-a)/(r - 1) s = np.array(range(r)) s = a + h * (s - 1) w = np.zeros(r, dtype = np.float64) for alpha in xrange(r): w[alpha] = 2*h * np.exp(beta*s[alpha]) / gamma(beta/2) w[0] = w[0]/2 w[r-1] = w[r-1]/2 U1 = np.zeros((N[0], r), dtype=np.float64) U2 = np.zeros((N[0], r), dtype=np.float64) U3 = np.zeros((N[0], r), dtype=np.float64) for alpha in xrange(r): U1[:, alpha] = np.exp(-(x-vec[0])**2 * np.exp(2*s[alpha])) U2[:, alpha] = np.exp(-(x-vec[1])**2 * np.exp(2*s[alpha])) U3[:, alpha] = np.exp(-(x-vec[2])**2 * np.exp(2*s[alpha])) newton = tuck.can2tuck(w, U1, U2, U3) newton = tuck.round(newton, eps) return newton
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*self.rho)*(x[1]-x[0])**3 + dE_nuc
def coulomb(x, vec, ind, eps, beta=1.0): # 1/|r-vec|**beta in Tucker format if ind == 6: a, b, r = -15., 10, 80 elif ind == 8: a, b, r = -20., 15, 145 elif ind == 10: a, b, r = -25., 20, 220 elif ind == 12: a, b, r = -30., 25, 320 else: raise Exception("wrong ind parameter") N = x.shape h = (b - a) / (r - 1) s = np.array(range(r)) s = a + h * (s - 1) w = np.zeros(r, dtype=np.float64) for alpha in xrange(r): w[alpha] = 2 * h * np.exp(beta * s[alpha]) / gamma(beta / 2) w[0] = w[0] / 2 w[r - 1] = w[r - 1] / 2 U1 = np.zeros((N[0], r), dtype=np.float64) U2 = np.zeros((N[0], r), dtype=np.float64) U3 = np.zeros((N[0], r), dtype=np.float64) for alpha in xrange(r): U1[:, alpha] = np.exp(-(x - vec[0])**2 * np.exp(2 * s[alpha])) U2[:, alpha] = np.exp(-(x - vec[1])**2 * np.exp(2 * s[alpha])) U3[:, alpha] = np.exp(-(x - vec[2])**2 * np.exp(2 * s[alpha])) newton = tuck.can2tuck(w, U1, U2, U3) newton = tuck.round(newton, eps) return newton
h = (b - a) / (N - 1) x = np.zeros(N) for i in xrange(N): x[i] = a + i * h def slater_fun((i, j, k)): return np.exp(-(x[i]**2 + x[j]**2 + x[k]**2)**0.5) def gaussian_fun((i, j, k)): return np.exp(-(x[i]**2 + x[j]**2 + x[k]**2)) print 'Converting tensors in the Tucker format...' print '(significantly faster version to be updated soon)' a = tuck.cross.cross3d(slater_fun, N, eps) b = tuck.cross.cross3d(gaussian_fun, N, eps) print 'Converting is done' print 'tensor a: %s' % (a) print 'tensor b: %s' % (b) print 'tensor 2a: %s' % (2 * a) print 'tensor a+a: %s' % (a + a) print 'tensor a+a after rounding: %s' % (tuck.round(a + a, eps)) print 'relative Frobenius norm of a-a: %s' % (tuck.norm(a - a) / tuck.norm(a)) # Warning! for big mode sizes (N >~ 256) full tensors may be out of memory. # So, use tensor_full function carefully.
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 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 gaussian_fun((i,j,k)): return np.exp(-(x[i]**2 + x[j]**2 + x[k]**2)) print 'Converting tensors in the Tucker format...' print '(significantly faster version to be updated soon)' a = tuck.cross.cross3d(slater_fun, N, eps) b = tuck.cross.cross3d(gaussian_fun, N, eps) print 'Converting is done' print 'tensor a: %s' % (a) print 'tensor b: %s' % (b) print 'tensor 2a: %s' % (2*a) print 'tensor a+a: %s' % (a + a) print 'tensor a+a after rounding: %s' % (tuck.round(a+a, eps)) print 'relative Frobenius norm of a-a: %s' % (tuck.norm(a-a)/tuck.norm(a)) # Warning! for big mode sizes (N >~ 256) full tensors may be out of memory. # So, use tensor_full function carefully.
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 cross3d(func, M, eps_init, delta_add = 1e-5): N = int((M+1)/2) r1 = 2 r2 = 2 r3 = 2 GG = np.zeros((r1,r2,r3),dtype=np.complex128) U1 = np.zeros((M,r1),dtype=np.complex128) U2 = np.zeros((M,r2),dtype=np.complex128) U3 = np.zeros((M,r3),dtype=np.complex128) U1[:N,:] = np.random.random((N,r1)) U2[:N,:] = np.random.random((N,r2)) U3[:N,:] = np.random.random((N,r3)) U1, R = np.linalg.qr(U1) U2, R = np.linalg.qr(U2) U3, R = np.linalg.qr(U3) eps_cross = 1 while True: row_order_U1 = tuck.mv.maxvol(U1) row_order_U2 = tuck.mv.maxvol(U2) row_order_U3 = tuck.mv.maxvol(U3) Ar = np.zeros((r1,r2,r3),dtype=np.complex128) for i in xrange(r1): for j in xrange(r2): for k in xrange(r3): Ar[i,j,k] = func((row_order_U1[i],row_order_U2[j],row_order_U3[k])) U1_r = U1[row_order_U1,:] U2_r = U2[row_order_U2,:] U3_r = U3[row_order_U3,:] G_UV = np.linalg.solve(U3_r,np.reshape(np.transpose(Ar,[2,0,1]),(r3,r1*r2),order='f')) G_UV = np.reshape(G_UV,(r3,r1,r2),order='f') G_UV = np.transpose(G_UV,[1,2,0]) G_U = np.linalg.solve(U2_r,np.reshape(np.transpose(G_UV,[1,2,0]),(r2,r1*r3),order='f')) G_U = np.reshape(G_U,(r2,r3,r1),order='f') G_U = np.transpose(G_U,[2,0,1]) G = np.linalg.solve(U1_r,np.reshape(G_U,(r1,r2*r3),order='f')) G = np.reshape(G,(r1,r2,r3),order='f') norm = np.linalg.norm(G) eps_cross = (np.linalg.norm(GG-G))/norm #print 'relative accuracy = %s' % (eps_cross), 'ranks = %s' % r1, r2, r3 G_Tucker = tuck.tensor(G, eps_init/10) G = G_Tucker.core U1 = np.dot(U1, G_Tucker.u[0]) U2 = np.dot(U2, G_Tucker.u[1]) U3 = np.dot(U3, G_Tucker.u[2]) (r1, r2, r3) = G_Tucker.r if eps_cross < eps_init: break row_order_U1 = tuck.mv.maxvol(U1) row_order_U2 = tuck.mv.maxvol(U2) row_order_U3 = tuck.mv.maxvol(U3) Ar = np.zeros((r1,r2,r3),dtype=np.complex128) for i in xrange(r1): for j in xrange(r2): for k in xrange(r3): Ar[i, j, k] = func((row_order_U1[i], row_order_U2[j], row_order_U3[k])) A1 = np.reshape(Ar, [r1,-1], order='f') A1_r = np.transpose(A1) A1_r,R = np.linalg.qr(A1_r) column_order_U1 = tuck.mv.maxvol(A1_r) A2 = np.reshape(np.transpose(Ar, [1,0,2]), [r2,-1], order='f') A2_r = np.transpose(A2) A2_r,R = np.linalg.qr(A2_r) column_order_U2 = tuck.mv.maxvol(A2_r) A3 = np.reshape(np.transpose(Ar, [2,0,1]), [r3,-1], order='f') A3_r = np.transpose(A3) A3_r,R = np.linalg.qr(A3_r) column_order_U3 = tuck.mv.maxvol(A3_r) u1 = np.zeros((M, r1), dtype=np.complex128) for i in xrange(r1): for ii in xrange(M): k1_order, j1_order = mod(column_order_U1[i], r2) u1[ii,i] = func((ii, row_order_U2[j1_order], row_order_U3[k1_order])) u2 = np.zeros((M, r2), dtype=np.complex128) for j in xrange(r2): for jj in xrange(M): k1_order, i1_order = mod(column_order_U2[j], r1) u2[jj,j] = func((row_order_U1[i1_order], jj, row_order_U3[k1_order])) u3 = np.zeros((M, r3), dtype=np.complex128) for k in xrange(r3): for kk in xrange(M): j1_order, i1_order = mod(column_order_U3[k], r1) u3[kk,k] = func((row_order_U1[i1_order], row_order_U2[j1_order], kk)) u1, v, r11 = round_matrix(u1, delta_add) u2, v, r22 = round_matrix(u2, delta_add) u3, v, r33 = round_matrix(u3, delta_add) u1 = u1[:,:r11] u2 = u2[:,:r22] u3 = u3[:,:r33] U1_0 = np.zeros((M,r1+r11),dtype=np.complex128) U2_0 = np.zeros((M,r2+r22),dtype=np.complex128) U3_0 = np.zeros((M,r3+r33),dtype=np.complex128) U1_0[:,:r1] = U1.copy() U2_0[:,:r2] = U2.copy() U3_0[:,:r3] = U3.copy() U1_0[:,r1:r1+r11] = u1 U2_0[:,r2:r2+r22] = u2 U3_0[:,r3:r3+r33] = u3 U1 = U1_0.copy() U2 = U2_0.copy() U3 = U3_0.copy() r1 = r1+r11 r2 = r2+r22 r3 = r3+r33 U1, R1 = np.linalg.qr(U1) U2, R2 = np.linalg.qr(U2) U3, R3 = np.linalg.qr(U3) GG = np.zeros((r1,r2,r3),dtype=np.complex128) GG[:(r1-r11),:(r2-r22),:(r3-r33)] = G.copy() GG = np.dot(np.transpose(GG,[2,1,0]),np.transpose(R1)) GG = np.dot(np.transpose(GG,[0,2,1]),np.transpose(R2)) GG = np.transpose(GG,[1,2,0]) GG = np.dot(GG,np.transpose(R3)) #print 'ranks after rounding = %s' % r1, r2, r3 G_Tucker.n = (M, M, M) G_Tucker.u[0] = U1 G_Tucker.u[1] = U2 G_Tucker.u[2] = U3 G_Tucker.r = [r1, r2, r3] return tuck.round(G_Tucker, eps_init)
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 cross3d(func, M, eps_init, delta_add=1e-5): N = int((M + 1) / 2) r1 = 2 r2 = 2 r3 = 2 GG = np.zeros((r1, r2, r3), dtype=np.complex128) U1 = np.zeros((M, r1), dtype=np.complex128) U2 = np.zeros((M, r2), dtype=np.complex128) U3 = np.zeros((M, r3), dtype=np.complex128) U1[:N, :] = np.random.random((N, r1)) U2[:N, :] = np.random.random((N, r2)) U3[:N, :] = np.random.random((N, r3)) U1, R = np.linalg.qr(U1) U2, R = np.linalg.qr(U2) U3, R = np.linalg.qr(U3) eps_cross = 1 while True: row_order_U1 = tuck.mv.maxvol(U1) row_order_U2 = tuck.mv.maxvol(U2) row_order_U3 = tuck.mv.maxvol(U3) Ar = np.zeros((r1, r2, r3), dtype=np.complex128) for i in xrange(r1): for j in xrange(r2): for k in xrange(r3): Ar[i, j, k] = func( (row_order_U1[i], row_order_U2[j], row_order_U3[k])) U1_r = U1[row_order_U1, :] U2_r = U2[row_order_U2, :] U3_r = U3[row_order_U3, :] G_UV = np.linalg.solve( U3_r, np.reshape(np.transpose(Ar, [2, 0, 1]), (r3, r1 * r2), order='f')) G_UV = np.reshape(G_UV, (r3, r1, r2), order='f') G_UV = np.transpose(G_UV, [1, 2, 0]) G_U = np.linalg.solve( U2_r, np.reshape(np.transpose(G_UV, [1, 2, 0]), (r2, r1 * r3), order='f')) G_U = np.reshape(G_U, (r2, r3, r1), order='f') G_U = np.transpose(G_U, [2, 0, 1]) G = np.linalg.solve(U1_r, np.reshape(G_U, (r1, r2 * r3), order='f')) G = np.reshape(G, (r1, r2, r3), order='f') norm = np.linalg.norm(G) eps_cross = (np.linalg.norm(GG - G)) / norm #print 'relative accuracy = %s' % (eps_cross), 'ranks = %s' % r1, r2, r3 G_Tucker = tuck.tensor(G, eps_init / 10) G = G_Tucker.core U1 = np.dot(U1, G_Tucker.u[0]) U2 = np.dot(U2, G_Tucker.u[1]) U3 = np.dot(U3, G_Tucker.u[2]) (r1, r2, r3) = G_Tucker.r if eps_cross < eps_init: break row_order_U1 = tuck.mv.maxvol(U1) row_order_U2 = tuck.mv.maxvol(U2) row_order_U3 = tuck.mv.maxvol(U3) Ar = np.zeros((r1, r2, r3), dtype=np.complex128) for i in xrange(r1): for j in xrange(r2): for k in xrange(r3): Ar[i, j, k] = func( (row_order_U1[i], row_order_U2[j], row_order_U3[k])) A1 = np.reshape(Ar, [r1, -1], order='f') A1_r = np.transpose(A1) A1_r, R = np.linalg.qr(A1_r) column_order_U1 = tuck.mv.maxvol(A1_r) A2 = np.reshape(np.transpose(Ar, [1, 0, 2]), [r2, -1], order='f') A2_r = np.transpose(A2) A2_r, R = np.linalg.qr(A2_r) column_order_U2 = tuck.mv.maxvol(A2_r) A3 = np.reshape(np.transpose(Ar, [2, 0, 1]), [r3, -1], order='f') A3_r = np.transpose(A3) A3_r, R = np.linalg.qr(A3_r) column_order_U3 = tuck.mv.maxvol(A3_r) u1 = np.zeros((M, r1), dtype=np.complex128) for i in xrange(r1): for ii in xrange(M): k1_order, j1_order = mod(column_order_U1[i], r2) u1[ii, i] = func( (ii, row_order_U2[j1_order], row_order_U3[k1_order])) u2 = np.zeros((M, r2), dtype=np.complex128) for j in xrange(r2): for jj in xrange(M): k1_order, i1_order = mod(column_order_U2[j], r1) u2[jj, j] = func( (row_order_U1[i1_order], jj, row_order_U3[k1_order])) u3 = np.zeros((M, r3), dtype=np.complex128) for k in xrange(r3): for kk in xrange(M): j1_order, i1_order = mod(column_order_U3[k], r1) u3[kk, k] = func( (row_order_U1[i1_order], row_order_U2[j1_order], kk)) u1, v, r11 = round_matrix(u1, delta_add) u2, v, r22 = round_matrix(u2, delta_add) u3, v, r33 = round_matrix(u3, delta_add) u1 = u1[:, :r11] u2 = u2[:, :r22] u3 = u3[:, :r33] U1_0 = np.zeros((M, r1 + r11), dtype=np.complex128) U2_0 = np.zeros((M, r2 + r22), dtype=np.complex128) U3_0 = np.zeros((M, r3 + r33), dtype=np.complex128) U1_0[:, :r1] = U1.copy() U2_0[:, :r2] = U2.copy() U3_0[:, :r3] = U3.copy() U1_0[:, r1:r1 + r11] = u1 U2_0[:, r2:r2 + r22] = u2 U3_0[:, r3:r3 + r33] = u3 U1 = U1_0.copy() U2 = U2_0.copy() U3 = U3_0.copy() r1 = r1 + r11 r2 = r2 + r22 r3 = r3 + r33 U1, R1 = np.linalg.qr(U1) U2, R2 = np.linalg.qr(U2) U3, R3 = np.linalg.qr(U3) GG = np.zeros((r1, r2, r3), dtype=np.complex128) GG[:(r1 - r11), :(r2 - r22), :(r3 - r33)] = G.copy() GG = np.dot(np.transpose(GG, [2, 1, 0]), np.transpose(R1)) GG = np.dot(np.transpose(GG, [0, 2, 1]), np.transpose(R2)) GG = np.transpose(GG, [1, 2, 0]) GG = np.dot(GG, np.transpose(R3)) #print 'ranks after rounding = %s' % r1, r2, r3 G_Tucker.n = (M, M, M) G_Tucker.u[0] = U1 G_Tucker.u[1] = U2 G_Tucker.u[2] = U3 G_Tucker.r = [r1, r2, r3] return tuck.round(G_Tucker, eps_init)
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 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 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 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