def poisson(self, n_g, l=0): # Old C version vr_g = self.zeros() nrdr_g = n_g * self.r_g * self.dr_g beta = self.a / self.b ng = int(round(1.0 / self.b)) assert abs(ng - 1 / self.b) < 1e-5 hartree(l, nrdr_g, beta, ng, vr_g) #vrp_g = self.purepythonpoisson(n_g,l) #assert abs(vr_g-vrp_g).max() < 1e-12 return vr_g
def atomic_exact_exchange(atom, type='all'): """Returns the exact exchange energy of the atom defined by the instantiated AllElectron object 'atom' """ G_LLL = gaunt(lmax=max(atom.l_j)) # Make gaunt coeff. list Nj = len(atom.n_j) # The total number of orbitals # determine relevant states for chosen type of exchange contribution if type == 'all': nstates = mstates = range(Nj) else: Njcore = core_states(atom.symbol) # The number of core orbitals if type == 'val-val': nstates = mstates = range(Njcore, Nj) elif type == 'core-core': nstates = mstates = range(Njcore) elif type == 'val-core': nstates = range(Njcore, Nj) mstates = range(Njcore) else: raise RuntimeError('Unknown type of exchange: ', type) # Arrays for storing the potential (times radius) vr = np.zeros(atom.N) vrl = np.zeros(atom.N) # do actual calculation of exchange contribution Exx = 0.0 for j1 in nstates: # angular momentum of first state l1 = atom.l_j[j1] for j2 in mstates: # angular momentum of second state l2 = atom.l_j[j2] # joint occupation number f12 = 0.5 * (atom.f_j[j1] / (2. * l1 + 1) * atom.f_j[j2] / (2. * l2 + 1)) # electron density times radius times length element nrdr = atom.u_j[j1] * atom.u_j[j2] * atom.dr nrdr[1:] /= atom.r[1:] # potential times radius vr[:] = 0.0 # L summation for l in range(l1 + l2 + 1): # get potential for current l-value hartree(l, nrdr, atom.r, vrl) # take all m1 m2 and m values of Gaunt matrix of the form # G(L1,L2,L) where L = {l,m} G2 = G_LLL[l1**2:(l1 + 1)**2, l2**2:(l2 + 1)**2, l**2:(l + 1)**2]**2 # add to total potential vr += vrl * np.sum(G2) # add to total exchange the contribution from current two states Exx += -.5 * f12 * np.dot(vr, nrdr) # double energy if mixed contribution if type == 'val-core': Exx *= 2. # return exchange energy return Exx
def constructX(gen): """Construct the X_p^a matrix for the given atom. The X_p^a matrix describes the valence-core interactions of the partial waves. """ # initialize attributes uv_j = gen.vu_j # soft valence states * r: lv_j = gen.vl_j # their repective l quantum numbers Nvi = 0 for l in lv_j: Nvi += 2 * l + 1 # total number of valence states (including m) # number of core and valence orbitals (j only, i.e. not m-number) Njcore = gen.njcore Njval = len(lv_j) # core states * r: uc_j = gen.u_j[:Njcore] r, dr, N, beta = gen.r, gen.dr, gen.N, gen.beta # potential times radius vr = np.zeros(N) # initialize X_ii matrix X_ii = np.zeros((Nvi, Nvi)) # make gaunt coeff. list lmax = max(gen.l_j[:Njcore] + gen.vl_j) gaunt = make_gaunt(lmax=lmax) # sum over core states for jc in range(Njcore): lc = gen.l_j[jc] # sum over first valence state index i1 = 0 for jv1 in range(Njval): lv1 = lv_j[jv1] # electron density 1 times radius times length element n1c = uv_j[jv1] * uc_j[jc] * dr n1c[1:] /= r[1:] # sum over second valence state index i2 = 0 for jv2 in range(Njval): lv2 = lv_j[jv2] # electron density 2 n2c = uv_j[jv2] * uc_j[jc] * dr n2c[1:] /= r[1:] # sum expansion in angular momenta for l in range(min(lv1, lv2) + lc + 1): # Int density * potential * r^2 * dr: hartree(l, n2c, beta, N, vr) nv = np.dot(n1c, vr) # expansion coefficients A_mm = X_ii[i1:i1 + 2 * lv1 + 1, i2:i2 + 2 * lv2 + 1] for mc in range(2 * lc + 1): for m in range(2 * l + 1): G1c = gaunt[lv1**2:(lv1 + 1)**2, lc**2 + mc, l**2 + m] G2c = gaunt[lv2**2:(lv2 + 1)**2, lc**2 + mc, l**2 + m] A_mm += nv * np.outer(G1c, G2c) i2 += 2 * lv2 + 1 i1 += 2 * lv1 + 1 # pack X_ii matrix X_p = pack2(X_ii) return X_p
def atomic_exact_exchange(atom, type = 'all'): """Returns the exact exchange energy of the atom defined by the instantiated AllElectron object 'atom' """ gaunt = make_gaunt(lmax=max(atom.l_j)) # Make gaunt coeff. list Nj = len(atom.n_j) # The total number of orbitals # determine relevant states for chosen type of exchange contribution if type == 'all': nstates = mstates = range(Nj) else: Njcore = core_states(atom.symbol) # The number of core orbitals if type == 'val-val': nstates = mstates = range(Njcore, Nj) elif type == 'core-core': nstates = mstates = range(Njcore) elif type == 'val-core': nstates = range(Njcore,Nj) mstates = range(Njcore) else: raise RuntimeError('Unknown type of exchange: ', type) # Arrays for storing the potential (times radius) vr = np.zeros(atom.N) vrl = np.zeros(atom.N) # do actual calculation of exchange contribution Exx = 0.0 for j1 in nstates: # angular momentum of first state l1 = atom.l_j[j1] for j2 in mstates: # angular momentum of second state l2 = atom.l_j[j2] # joint occupation number f12 = .5 * atom.f_j[j1] / (2. * l1 + 1) * \ atom.f_j[j2] / (2. * l2 + 1) # electron density times radius times length element nrdr = atom.u_j[j1] * atom.u_j[j2] * atom.dr nrdr[1:] /= atom.r[1:] # potential times radius vr[:] = 0.0 # L summation for l in range(l1 + l2 + 1): # get potential for current l-value hartree(l, nrdr, atom.beta, atom.N, vrl) # take all m1 m2 and m values of Gaunt matrix of the form # G(L1,L2,L) where L = {l,m} G2 = gaunt[l1**2:(l1+1)**2, l2**2:(l2+1)**2, l**2:(l+1)**2]**2 # add to total potential vr += vrl * np.sum(G2) # add to total exchange the contribution from current two states Exx += -.5 * f12 * np.dot(vr, nrdr) # double energy if mixed contribution if type == 'val-core': Exx *= 2. # return exchange energy return Exx
def poisson(self, n_g, l=0): vr_g = self.zeros() nrdr_g = n_g * self.r_g * self.dr_g hartree(l, nrdr_g, self.r_g, vr_g) return vr_g
def run(self, core='', rcut=1.0, extra=None, logderiv=False, vbar=None, exx=False, name=None, normconserving='', filter=(0.4, 1.75), rcutcomp=None, write_xml=True, use_restart_file=True, empty_states=''): self.name = name self.core = core if type(rcut) is float: rcut_l = [rcut] else: rcut_l = rcut rcutmax = max(rcut_l) rcutmin = min(rcut_l) self.rcut_l = rcut_l if rcutcomp is None: rcutcomp = rcutmin self.rcutcomp = rcutcomp hfilter, xfilter = filter Z = self.Z n_j = self.n_j l_j = self.l_j f_j = self.f_j e_j = self.e_j if vbar is None: vbar = ('poly', rcutmin * 0.9) vbar_type, rcutvbar = vbar normconserving_l = [x in normconserving for x in 'spdf'] # Parse core string: j = 0 if core.startswith('['): a, core = core.split(']') core_symbol = a[1:] j = len(configurations[core_symbol][1]) while core != '': assert n_j[j] == int(core[0]) assert l_j[j] == 'spdf'.find(core[1]) if j != self.jcorehole: assert f_j[j] == 2 * (2 * l_j[j] + 1) j += 1 core = core[2:] njcore = j self.njcore = njcore lmaxocc = max(l_j[njcore:]) while empty_states != '': n = int(empty_states[0]) l = 'spdf'.find(empty_states[1]) assert n == 1 + l + l_j.count(l) n_j.append(n) l_j.append(l) f_j.append(0.0) e_j.append(-0.01) empty_states = empty_states[2:] if 2 in l_j[njcore:]: # We have a bound valence d-state. Add bound s- and # p-states if not already there: for l in [0, 1]: if l not in l_j[njcore:]: n_j.append(1 + l + l_j.count(l)) l_j.append(l) f_j.append(0.0) e_j.append(-0.01) if l_j[njcore:] == [0] and Z > 2: # We have only a bound valence s-state and we are not # hydrogen and not helium. Add bound p-state: n_j.append(n_j[njcore]) l_j.append(1) f_j.append(0.0) e_j.append(-0.01) nj = len(n_j) self.Nv = sum(f_j[njcore:]) self.Nc = sum(f_j[:njcore]) # Do all-electron calculation: AllElectron.run(self, use_restart_file) # Highest occupied atomic orbital: self.emax = max(e_j) N = self.N r = self.r dr = self.dr d2gdr2 = self.d2gdr2 beta = self.beta dv = r**2 * dr t = self.text t() t('Generating PAW setup') if core != '': t('Frozen core:', core) # So far - no ghost-states: self.ghost = False # Calculate the kinetic energy of the core states: Ekincore = 0.0 j = 0 for f, e, u in zip(f_j[:njcore], e_j[:njcore], self.u_j[:njcore]): u = np.where(abs(u) < 1e-160, 0, u) # XXX Numeric! k = e - np.sum((u**2 * self.vr * dr)[1:] / r[1:]) Ekincore += f * k if j == self.jcorehole: self.Ekincorehole = k j += 1 # Calculate core density: if njcore == 0: nc = np.zeros(N) else: uc_j = self.u_j[:njcore] uc_j = np.where(abs(uc_j) < 1e-160, 0, uc_j) # XXX Numeric! nc = np.dot(f_j[:njcore], uc_j**2) / (4 * pi) nc[1:] /= r[1:]**2 nc[0] = nc[1] self.nc = nc # Calculate core kinetic energy density if njcore == 0: tauc = np.zeros(N) else: tauc = self.radial_kinetic_energy_density(f_j[:njcore], l_j[:njcore], self.u_j[:njcore]) t('Kinetic energy of the core from tauc =', np.dot(tauc * r * r, dr) * 4 * pi) lmax = max(l_j[njcore:]) # Order valence states with respect to angular momentum # quantum number: self.n_ln = n_ln = [] self.f_ln = f_ln = [] self.e_ln = e_ln = [] for l in range(lmax + 1): n_n = [] f_n = [] e_n = [] for j in range(njcore, nj): if l_j[j] == l: n_n.append(n_j[j]) f_n.append(f_j[j]) e_n.append(e_j[j]) n_ln.append(n_n) f_ln.append(f_n) e_ln.append(e_n) # Add extra projectors: if extra is not None: if len(extra) == 0: lmaxextra = 0 else: lmaxextra = max(extra.keys()) if lmaxextra > lmax: for l in range(lmax, lmaxextra): n_ln.append([]) f_ln.append([]) e_ln.append([]) lmax = lmaxextra for l in extra: nn = -1 for e in extra[l]: n_ln[l].append(nn) f_ln[l].append(0.0) e_ln[l].append(e) nn -= 1 else: # Automatic: # Make sure we have two projectors for each occupied channel: for l in range(lmaxocc + 1): if len(n_ln[l]) < 2 and not normconserving_l[l]: # Only one - add one more: assert len(n_ln[l]) == 1 n_ln[l].append(-1) f_ln[l].append(0.0) e_ln[l].append(1.0 + e_ln[l][0]) if lmaxocc < 2 and lmaxocc == lmax: # Add extra projector for l = lmax + 1: n_ln.append([-1]) f_ln.append([0.0]) e_ln.append([0.0]) lmax += 1 self.lmax = lmax rcut_l.extend([rcutmin] * (lmax + 1 - len(rcut_l))) t('Cutoffs:') for rc, s in zip(rcut_l, 'spdf'): t('rc(%s)=%.3f' % (s, rc)) t('rc(vbar)=%.3f' % rcutvbar) t('rc(comp)=%.3f' % rcutcomp) t('rc(nct)=%.3f' % rcutmax) t() t('Kinetic energy of the core states: %.6f' % Ekincore) # Allocate arrays: self.u_ln = u_ln = [] # phi * r self.s_ln = s_ln = [] # phi-tilde * r self.q_ln = q_ln = [] # p-tilde * r for l in range(lmax + 1): nn = len(n_ln[l]) u_ln.append(np.zeros((nn, N))) s_ln.append(np.zeros((nn, N))) q_ln.append(np.zeros((nn, N))) # Fill in all-electron wave functions: for l in range(lmax + 1): # Collect all-electron wave functions: u_n = [self.u_j[j] for j in range(njcore, nj) if l_j[j] == l] for n, u in enumerate(u_n): u_ln[l][n] = u # Grid-index corresponding to rcut: gcut_l = [1 + int(rc * N / (rc + beta)) for rc in rcut_l] rcutfilter = xfilter * rcutmax self.rcutfilter = rcutfilter gcutfilter = 1 + int(rcutfilter * N / (rcutfilter + beta)) gcutmax = 1 + int(rcutmax * N / (rcutmax + beta)) # Outward integration of unbound states stops at 3 * rcut: gmax = int(3 * rcutmax * N / (3 * rcutmax + beta)) assert gmax > gcutfilter # Calculate unbound extra states: c2 = -(r / dr)**2 c10 = -d2gdr2 * r**2 for l, (n_n, e_n, u_n) in enumerate(zip(n_ln, e_ln, u_ln)): for n, e, u in zip(n_n, e_n, u_n): if n < 0: u[:] = 0.0 shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gmax) u *= 1.0 / u[gcut_l[l]] charge = Z - self.Nv - self.Nc t('Charge: %.1f' % charge) t('Core electrons: %.1f' % self.Nc) t('Valence electrons: %.1f' % self.Nv) # Construct smooth wave functions: coefs = [] for l, (u_n, s_n) in enumerate(zip(u_ln, s_ln)): nodeless = True gc = gcut_l[l] for u, s in zip(u_n, s_n): s[:] = u if normconserving_l[l]: A = np.zeros((5, 5)) A[:4, 0] = 1.0 A[:4, 1] = r[gc - 2:gc + 2]**2 A[:4, 2] = A[:4, 1]**2 A[:4, 3] = A[:4, 1] * A[:4, 2] A[:4, 4] = A[:4, 2]**2 A[4, 4] = 1.0 a = u[gc - 2:gc + 3] / r[gc - 2:gc + 3]**(l + 1) a = np.log(a) def f(x): a[4] = x b = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = b[0] + r2 * (b[1] + r2 * (b[2] + r2 * (b[3] + r2 * b[4]))) y = np.exp(y) s[:gc] = rl1 * y return np.dot(s**2, dr) - 1 x1 = 0.0 x2 = 0.001 f1 = f(x1) f2 = f(x2) while abs(f1) > 1e-6: x0 = (x1 / f1 - x2 / f2) / (1 / f1 - 1 / f2) f0 = f(x0) if abs(f1) < abs(f2): x2, f2 = x1, f1 x1, f1 = x0, f0 else: A = np.ones((4, 4)) A[:, 0] = 1.0 A[:, 1] = r[gc - 2:gc + 2]**2 A[:, 2] = A[:, 1]**2 A[:, 3] = A[:, 1] * A[:, 2] a = u[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1) if 0:#l < 2 and nodeless: a = np.log(a) a = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * (a[3]))) if 0:#l < 2 and nodeless: y = np.exp(y) s[:gc] = rl1 * y coefs.append(a) if nodeless: if not np.alltrue(s[1:gc] > 0.0): raise RuntimeError( 'Error: The %d%s pseudo wave has a node!' % (n_ln[l][0], 'spdf'[l])) # Only the first state for each l must be nodeless: nodeless = False # Calculate pseudo core density: gcutnc = 1 + int(rcutmax * N / (rcutmax + beta)) self.nct = nct = nc.copy() A = np.ones((4, 4)) A[0] = 1.0 A[1] = r[gcutnc - 2:gcutnc + 2]**2 A[2] = A[1]**2 A[3] = A[1] * A[2] a = nc[gcutnc - 2:gcutnc + 2] a = solve(np.transpose(A), a) r2 = r[:gcutnc]**2 nct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3])) t('Pseudo-core charge: %.6f' % (4 * pi * np.dot(nct, dv))) # ... and the pseudo core kinetic energy density: tauct = tauc.copy() a = tauc[gcutnc - 2:gcutnc + 2] a = solve(np.transpose(A), a) tauct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3])) # ... and the soft valence density: nt = np.zeros(N) for f_n, s_n in zip(f_ln, s_ln): nt += np.dot(f_n, s_n**2) / (4 * pi) nt[1:] /= r[1:]**2 nt[0] = nt[1] nt += nct self.nt = nt # Calculate the shape function: x = r / rcutcomp gaussian = np.zeros(N) self.gamma = gamma = 10.0 gaussian[:gmax] = np.exp(-gamma * x[:gmax]**2) gt = 4 * (gamma / rcutcomp**2)**1.5 / sqrt(pi) * gaussian t('Shape function alpha=%.3f' % (gamma / rcutcomp**2)) norm = np.dot(gt, dv) #print norm, norm-1 assert abs(norm - 1) < 1e-2 gt /= norm # Calculate smooth charge density: Nt = np.dot(nt, dv) rhot = nt - (Nt + charge / (4 * pi)) * gt t('Pseudo-electron charge', 4 * pi * Nt) vHt = np.zeros(N) hartree(0, rhot * r * dr, self.beta, self.N, vHt) vHt[1:] /= r[1:] vHt[0] = vHt[1] vXCt = np.zeros(N) extra_xc_data = {} if self.xc.type != 'GLLB': Exct = self.xc.calculate_spherical(self.rgd, nt.reshape((1, -1)), vXCt.reshape((1, -1))) else: Exct = self.xc.get_smooth_xc_potential_and_energy_1d(vXCt) # Calculate extra-stuff for non-local functionals self.xc.get_extra_setup_data(extra_xc_data) vt = vHt + vXCt # Construct zero potential: gc = 1 + int(rcutvbar * N / (rcutvbar + beta)) if vbar_type == 'f': assert lmax == 2 uf = np.zeros(N) l = 3 # Solve for all-electron f-state: eps = 0.0 shoot(uf, l, self.vr, eps, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gmax) uf *= 1.0 / uf[gc] # Fit smooth pseudo f-state polynomium: A = np.ones((4, 4)) A[:, 0] = 1.0 A[:, 1] = r[gc - 2:gc + 2]**2 A[:, 2] = A[:, 1]**2 A[:, 3] = A[:, 1] * A[:, 2] a = uf[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1) a0, a1, a2, a3 = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = a0 + r2 * (a1 + r2 * (a2 + r2 * a3)) sf = uf.copy() sf[:gc] = rl1 * y # From 0 to gc, use analytic formula for kinetic energy operator: r4 = r2**2 r6 = r4 * r2 enumerator = (a0 * l * (l + 1) + a1 * (l + 2) * (l + 3) * r2 + a2 * (l + 4) * (l + 5) * r4 + a3 * (l + 6) * (l + 7) * r6) denominator = a0 + a1 * r2 + a2 * r4 + a3 * r6 ekin_over_phit = - 0.5 * (enumerator / denominator - l * (l + 1)) ekin_over_phit[1:] /= r2[1:] vbar = eps - vt vbar[:gc] -= ekin_over_phit vbar[0] = vbar[1] # Actually we can collect the terms into # a single fraction without poles, so as to avoid doing this, # but this is good enough # From gc to gmax, use finite-difference formula for kinetic # energy operator: vbar[gc:gmax] -= self.kin(l, sf)[gc:gmax] / sf[gc:gmax] vbar[gmax:] = 0.0 else: assert vbar_type == 'poly' A = np.ones((2, 2)) A[0] = 1.0 A[1] = r[gc - 1:gc + 1]**2 a = vt[gc - 1:gc + 1] a = solve(np.transpose(A), a) r2 = r**2 vbar = a[0] + r2 * a[1] - vt vbar[gc:] = 0.0 vt += vbar # Construct projector functions: for l, (e_n, s_n, q_n) in enumerate(zip(e_ln, s_ln, q_ln)): for e, s, q in zip(e_n, s_n, q_n): q[:] = self.kin(l, s) + (vt - e) * s q[gcutmax:] = 0.0 filter = Filter(r, dr, gcutfilter, hfilter).filter vbar = filter(vbar * r) # Calculate matrix elements: self.dK_lnn = dK_lnn = [] self.dH_lnn = dH_lnn = [] self.dO_lnn = dO_lnn = [] for l, (e_n, u_n, s_n, q_n) in enumerate(zip(e_ln, u_ln, s_ln, q_ln)): A_nn = np.inner(s_n, q_n * dr) # Do a LU decomposition of A: nn = len(e_n) L_nn = np.identity(nn, float) U_nn = A_nn.copy() # Keep all bound states normalized if sum([n > 0 for n in n_ln[l]]) <= 1: for i in range(nn): for j in range(i + 1, nn): L_nn[j, i] = 1.0 * U_nn[j, i] / U_nn[i, i] U_nn[j, :] -= U_nn[i, :] * L_nn[j, i] dO_nn = (np.inner(u_n, u_n * dr) - np.inner(s_n, s_n * dr)) e_nn = np.zeros((nn, nn)) e_nn.ravel()[::nn + 1] = e_n dH_nn = np.dot(dO_nn, e_nn) - A_nn q_n[:] = np.dot(inv(np.transpose(U_nn)), q_n) s_n[:] = np.dot(inv(L_nn), s_n) u_n[:] = np.dot(inv(L_nn), u_n) dO_nn = np.dot(np.dot(inv(L_nn), dO_nn), inv(np.transpose(L_nn))) dH_nn = np.dot(np.dot(inv(L_nn), dH_nn), inv(np.transpose(L_nn))) ku_n = [self.kin(l, u, e) for u, e in zip(u_n, e_n)] ks_n = [self.kin(l, s) for s in s_n] dK_nn = 0.5 * (np.inner(u_n, ku_n * dr) - np.inner(s_n, ks_n * dr)) dK_nn += np.transpose(dK_nn).copy() dK_lnn.append(dK_nn) dO_lnn.append(dO_nn) dH_lnn.append(dH_nn) for n, q in enumerate(q_n): q[:] = filter(q, l) * r**(l + 1) A_nn = np.inner(s_n, q_n * dr) q_n[:] = np.dot(inv(np.transpose(A_nn)), q_n) self.vt = vt self.vbar = vbar t('state eigenvalue norm') t('--------------------------------') for l, (n_n, f_n, e_n) in enumerate(zip(n_ln, f_ln, e_ln)): for n in range(len(e_n)): if n_n[n] > 0: f = '(%d)' % f_n[n] t('%d%s%-4s: %12.6f %12.6f' % ( n_n[n], 'spdf'[l], f, e_n[n], np.dot(s_ln[l][n]**2, dr))) else: t('*%s : %12.6f' % ('spdf'[l], e_n[n])) t('--------------------------------') self.logd = {} if logderiv: ni = 300 self.elog = np.linspace(-5.0, 1.0, ni) # Calculate logarithmic derivatives: gld = gcutmax + 10 self.rlog = r[gld] assert gld < gmax t('Calculating logarithmic derivatives at r=%.3f' % r[gld]) t('(skip with [Ctrl-C])') try: u = np.zeros(N) for l in range(4): self.logd[l] = (np.empty(ni), np.empty(ni)) if l <= lmax: dO_nn = dO_lnn[l] dH_nn = dH_lnn[l] q_n = q_ln[l] fae = open(self.symbol + '.ae.ld.' + 'spdf'[l], 'w') fps = open(self.symbol + '.ps.ld.' + 'spdf'[l], 'w') for i, e in enumerate(self.elog): # All-electron logarithmic derivative: u[:] = 0.0 shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gld) dudr = 0.5 * (u[gld + 1] - u[gld - 1]) / dr[gld] ld = dudr / u[gld] - 1.0 / r[gld] print >> fae, e, ld self.logd[l][0][i] = ld # PAW logarithmic derivative: s = self.integrate(l, vt, e, gld) if l <= lmax: A_nn = dH_nn - e * dO_nn s_n = [self.integrate(l, vt, e, gld, q) for q in q_n] B_nn = np.inner(q_n, s_n * dr) a_n = np.dot(q_n, s * dr) B_nn = np.dot(A_nn, B_nn) B_nn.ravel()[::len(a_n) + 1] += 1.0 c_n = solve(B_nn, np.dot(A_nn, a_n)) s -= np.dot(c_n, s_n) dsdr = 0.5 * (s[gld + 1] - s[gld - 1]) / dr[gld] ld = dsdr / s[gld] - 1.0 / r[gld] print >> fps, e, ld self.logd[l][1][i] = ld except KeyboardInterrupt: pass self.write(nc,'nc') self.write(nt, 'nt') self.write(nct, 'nct') self.write(vbar, 'vbar') self.write(vt, 'vt') self.write(tauc, 'tauc') self.write(tauct, 'tauct') for l, (n_n, f_n, u_n, s_n, q_n) in enumerate(zip(n_ln, f_ln, u_ln, s_ln, q_ln)): for n, f, u, s, q in zip(n_n, f_n, u_n, s_n, q_n): if n < 0: self.write(u, 'ae', n=n, l=l) self.write(s, 'ps', n=n, l=l) self.write(q, 'proj', n=n, l=l) # Test for ghost states: for h in [0.05]: self.diagonalize(h) self.vn_j = vn_j = [] self.vl_j = vl_j = [] self.vf_j = vf_j = [] self.ve_j = ve_j = [] self.vu_j = vu_j = [] self.vs_j = vs_j = [] self.vq_j = vq_j = [] j_ln = [[0 for f in f_n] for f_n in f_ln] j = 0 for l, n_n in enumerate(n_ln): for n, nn in enumerate(n_n): if nn > 0: vf_j.append(f_ln[l][n]) vn_j.append(nn) vl_j.append(l) ve_j.append(e_ln[l][n]) vu_j.append(u_ln[l][n]) vs_j.append(s_ln[l][n]) vq_j.append(q_ln[l][n]) j_ln[l][n] = j j += 1 for l, n_n in enumerate(n_ln): for n, nn in enumerate(n_n): if nn < 0: vf_j.append(0) vn_j.append(nn) vl_j.append(l) ve_j.append(e_ln[l][n]) vu_j.append(u_ln[l][n]) vs_j.append(s_ln[l][n]) vq_j.append(q_ln[l][n]) j_ln[l][n] = j j += 1 nj = j self.dK_jj = np.zeros((nj, nj)) for l, j_n in enumerate(j_ln): for n1, j1 in enumerate(j_n): for n2, j2 in enumerate(j_n): self.dK_jj[j1, j2] = self.dK_lnn[l][n1, n2] if exx: X_p = constructX(self) ExxC = atomic_exact_exchange(self, 'core-core') else: X_p = None ExxC = None sqrt4pi = sqrt(4 * pi) setup = SetupData(self.symbol, self.xc.name, self.name, readxml=False) def divide_by_r(x_g, l): r = self.r #for x_g, l in zip(x_jg, l_j): p = x_g.copy() p[1:] /= self.r[1:] # XXXXX go to higher order!!!!! if l == 0:#l_j[self.jcorehole] == 0: p[0] = (p[2] + (p[1] - p[2]) * (r[0] - r[2]) / (r[1] - r[2])) return p def divide_all_by_r(x_jg): return [divide_by_r(x_g, l) for x_g, l in zip(x_jg, vl_j)] setup.l_j = vl_j setup.n_j = vn_j setup.f_j = vf_j setup.eps_j = ve_j setup.rcut_j = [rcut_l[l] for l in vl_j] setup.nc_g = nc * sqrt4pi setup.nct_g = nct * sqrt4pi setup.nvt_g = (nt - nct) * sqrt4pi setup.e_kinetic_core = Ekincore setup.vbar_g = vbar * sqrt4pi setup.tauc_g = tauc * sqrt4pi setup.tauct_g = tauct * sqrt4pi setup.extra_xc_data = extra_xc_data setup.Z = Z setup.Nc = self.Nc setup.Nv = self.Nv setup.e_kinetic = self.Ekin setup.e_xc = self.Exc setup.e_electrostatic = self.Epot setup.e_total = self.Epot + self.Exc + self.Ekin setup.rgd = self.rgd setup.rcgauss = self.rcutcomp / sqrt(self.gamma) setup.e_kin_jj = self.dK_jj setup.ExxC = ExxC setup.phi_jg = divide_all_by_r(vu_j) setup.phit_jg = divide_all_by_r(vs_j) setup.pt_jg = divide_all_by_r(vq_j) setup.X_p = X_p if self.jcorehole is not None: setup.has_corehole = True setup.lcorehole = l_j[self.jcorehole] # l_j or vl_j ????? XXX setup.ncorehole = n_j[self.jcorehole] setup.phicorehole_g = divide_by_r(self.u_j[self.jcorehole], setup.lcorehole) setup.core_hole_e = self.e_j[self.jcorehole] setup.core_hole_e_kin = self.Ekincorehole setup.fcorehole = self.fcorehole if self.ghost: raise RuntimeError('Ghost!') if self.scalarrel: reltype = 'scalar-relativistic' else: reltype = 'non-relativistic' attrs = [('type', reltype), ('name', 'gpaw-%s' % version)] data = 'Frozen core: '+ (self.core or 'none') setup.generatorattrs = attrs setup.generatordata = data self.id_j = [] for l, n in zip(vl_j, vn_j): if n > 0: id = '%s-%d%s' % (self.symbol, n, 'spdf'[l]) else: id = '%s-%s%d' % (self.symbol, 'spdf'[l], -n) self.id_j.append(id) setup.id_j = self.id_j if write_xml: setup.write_xml() return setup
def run(self, core='', rcut=1.0, extra=None, logderiv=False, vbar=None, exx=False, name=None, normconserving='', filter=(0.4, 1.75), rcutcomp=None, write_xml=True, use_restart_file=True, empty_states=''): self.name = name self.core = core if type(rcut) is float: rcut_l = [rcut] else: rcut_l = rcut rcutmax = max(rcut_l) rcutmin = min(rcut_l) self.rcut_l = rcut_l if rcutcomp is None: rcutcomp = rcutmin self.rcutcomp = rcutcomp hfilter, xfilter = filter Z = self.Z n_j = self.n_j l_j = self.l_j f_j = self.f_j e_j = self.e_j if vbar is None: vbar = ('poly', rcutmin * 0.9) vbar_type, rcutvbar = vbar normconserving_l = [x in normconserving for x in 'spdf'] # Parse core string: j = 0 if core.startswith('['): a, core = core.split(']') core_symbol = a[1:] j = len(configurations[core_symbol][1]) while core != '': assert n_j[j] == int(core[0]) assert l_j[j] == 'spdf'.find(core[1]) if j != self.jcorehole: assert f_j[j] == 2 * (2 * l_j[j] + 1) j += 1 core = core[2:] njcore = j self.njcore = njcore lmaxocc = max(l_j[njcore:]) while empty_states != '': n = int(empty_states[0]) l = 'spdf'.find(empty_states[1]) print l_j assert n == 1 + l + l_j.count(l) n_j.append(n) l_j.append(l) f_j.append(0.0) e_j.append(-0.01) empty_states = empty_states[2:] if 2 in l_j[njcore:]: # We have a bound valence d-state. Add bound s- and # p-states if not already there: for l in [0, 1]: if l not in l_j[njcore:]: n_j.append(1 + l + l_j.count(l)) l_j.append(l) f_j.append(0.0) e_j.append(-0.01) if l_j[njcore:] == [0] and Z > 2: # We have only a bound valence s-state and we are not # hydrogen and not helium. Add bound p-state: n_j.append(n_j[njcore]) l_j.append(1) f_j.append(0.0) e_j.append(-0.01) nj = len(n_j) self.Nv = sum(f_j[njcore:]) self.Nc = sum(f_j[:njcore]) # Do all-electron calculation: AllElectron.run(self, use_restart_file) # Highest occupied atomic orbital: self.emax = max(e_j) N = self.N r = self.r dr = self.dr d2gdr2 = self.d2gdr2 beta = self.beta dv = r**2 * dr t = self.text t() t('Generating PAW setup') if core != '': t('Frozen core:', core) # So far - no ghost-states: self.ghost = False # Calculate the kinetic energy of the core states: Ekincore = 0.0 j = 0 for f, e, u in zip(f_j[:njcore], e_j[:njcore], self.u_j[:njcore]): u = np.where(abs(u) < 1e-160, 0, u) # XXX Numeric! k = e - np.sum((u**2 * self.vr * dr)[1:] / r[1:]) Ekincore += f * k if j == self.jcorehole: self.Ekincorehole = k j += 1 # Calculate core density: if njcore == 0: nc = np.zeros(N) else: uc_j = self.u_j[:njcore] uc_j = np.where(abs(uc_j) < 1e-160, 0, uc_j) # XXX Numeric! nc = np.dot(f_j[:njcore], uc_j**2) / (4 * pi) nc[1:] /= r[1:]**2 nc[0] = nc[1] self.nc = nc # Calculate core kinetic energy density if njcore == 0: tauc = np.zeros(N) else: tauc = self.radial_kinetic_energy_density(f_j[:njcore], l_j[:njcore], self.u_j[:njcore]) t('Kinetic energy of the core from tauc =', np.dot(tauc * r * r, dr) * 4 * pi) lmax = max(l_j[njcore:]) # Order valence states with respect to angular momentum # quantum number: self.n_ln = n_ln = [] self.f_ln = f_ln = [] self.e_ln = e_ln = [] for l in range(lmax + 1): n_n = [] f_n = [] e_n = [] for j in range(njcore, nj): if l_j[j] == l: n_n.append(n_j[j]) f_n.append(f_j[j]) e_n.append(e_j[j]) n_ln.append(n_n) f_ln.append(f_n) e_ln.append(e_n) # Add extra projectors: if extra is not None: if len(extra) == 0: lmaxextra = 0 else: lmaxextra = max(extra.keys()) if lmaxextra > lmax: for l in range(lmax, lmaxextra): n_ln.append([]) f_ln.append([]) e_ln.append([]) lmax = lmaxextra for l in extra: nn = -1 for e in extra[l]: n_ln[l].append(nn) f_ln[l].append(0.0) e_ln[l].append(e) nn -= 1 else: # Automatic: # Make sure we have two projectors for each occupied channel: for l in range(lmaxocc + 1): if len(n_ln[l]) < 2 and not normconserving_l[l]: # Only one - add one more: assert len(n_ln[l]) == 1 n_ln[l].append(-1) f_ln[l].append(0.0) e_ln[l].append(1.0 + e_ln[l][0]) if lmaxocc < 2 and lmaxocc == lmax: # Add extra projector for l = lmax + 1: n_ln.append([-1]) f_ln.append([0.0]) e_ln.append([0.0]) lmax += 1 self.lmax = lmax rcut_l.extend([rcutmin] * (lmax + 1 - len(rcut_l))) t('Cutoffs:') for rc, s in zip(rcut_l, 'spdf'): t('rc(%s)=%.3f' % (s, rc)) t('rc(vbar)=%.3f' % rcutvbar) t('rc(comp)=%.3f' % rcutcomp) t() t('Kinetic energy of the core states: %.6f' % Ekincore) # Allocate arrays: self.u_ln = u_ln = [] # phi * r self.s_ln = s_ln = [] # phi-tilde * r self.q_ln = q_ln = [] # p-tilde * r for l in range(lmax + 1): nn = len(n_ln[l]) u_ln.append(np.zeros((nn, N))) s_ln.append(np.zeros((nn, N))) q_ln.append(np.zeros((nn, N))) # Fill in all-electron wave functions: for l in range(lmax + 1): # Collect all-electron wave functions: u_n = [self.u_j[j] for j in range(njcore, nj) if l_j[j] == l] for n, u in enumerate(u_n): u_ln[l][n] = u # Grid-index corresponding to rcut: gcut_l = [1 + int(rc * N / (rc + beta)) for rc in rcut_l] rcutfilter = xfilter * rcutmax self.rcutfilter = rcutfilter gcutfilter = 1 + int(rcutfilter * N / (rcutfilter + beta)) gcutmax = 1 + int(rcutmax * N / (rcutmax + beta)) # Outward integration of unbound states stops at 3 * rcut: gmax = int(3 * rcutmax * N / (3 * rcutmax + beta)) assert gmax > gcutfilter # Calculate unbound extra states: c2 = -(r / dr)**2 c10 = -d2gdr2 * r**2 for l, (n_n, e_n, u_n) in enumerate(zip(n_ln, e_ln, u_ln)): for n, e, u in zip(n_n, e_n, u_n): if n < 0: u[:] = 0.0 shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gmax) u *= 1.0 / u[gcut_l[l]] charge = Z - self.Nv - self.Nc t('Charge: %.1f' % charge) t('Core electrons: %.1f' % self.Nc) t('Valence electrons: %.1f' % self.Nv) # Construct smooth wave functions: coefs = [] for l, (u_n, s_n) in enumerate(zip(u_ln, s_ln)): nodeless = True gc = gcut_l[l] for u, s in zip(u_n, s_n): s[:] = u if normconserving_l[l]: A = np.zeros((5, 5)) A[:4, 0] = 1.0 A[:4, 1] = r[gc - 2:gc + 2]**2 A[:4, 2] = A[:4, 1]**2 A[:4, 3] = A[:4, 1] * A[:4, 2] A[:4, 4] = A[:4, 2]**2 A[4, 4] = 1.0 a = u[gc - 2:gc + 3] / r[gc - 2:gc + 3]**(l + 1) a = np.log(a) def f(x): a[4] = x b = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = b[0] + r2 * (b[1] + r2 * (b[2] + r2 * (b[3] + r2 * b[4]))) y = np.exp(y) s[:gc] = rl1 * y return np.dot(s**2, dr) - 1 x1 = 0.0 x2 = 0.001 f1 = f(x1) f2 = f(x2) while abs(f1) > 1e-6: x0 = (x1 / f1 - x2 / f2) / (1 / f1 - 1 / f2) f0 = f(x0) if abs(f1) < abs(f2): x2, f2 = x1, f1 x1, f1 = x0, f0 else: A = np.ones((4, 4)) A[:, 0] = 1.0 A[:, 1] = r[gc - 2:gc + 2]**2 A[:, 2] = A[:, 1]**2 A[:, 3] = A[:, 1] * A[:, 2] a = u[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1) if 0: #l < 2 and nodeless: a = np.log(a) a = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * (a[3]))) if 0: #l < 2 and nodeless: y = np.exp(y) s[:gc] = rl1 * y coefs.append(a) if nodeless: if not np.alltrue(s[1:gc] > 0.0): raise RuntimeError( 'Error: The %d%s pseudo wave has a node!' % (n_ln[l][0], 'spdf'[l])) # Only the first state for each l must be nodeless: nodeless = False # Calculate pseudo core density: gcutnc = 1 + int(rcutmax * N / (rcutmax + beta)) self.nct = nct = nc.copy() A = np.ones((4, 4)) A[0] = 1.0 A[1] = r[gcutnc - 2:gcutnc + 2]**2 A[2] = A[1]**2 A[3] = A[1] * A[2] a = nc[gcutnc - 2:gcutnc + 2] a = solve(np.transpose(A), a) r2 = r[:gcutnc]**2 nct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3])) t('Pseudo-core charge: %.6f' % (4 * pi * np.dot(nct, dv))) # ... and the pseudo core kinetic energy density: tauct = tauc.copy() a = tauc[gcutnc - 2:gcutnc + 2] a = solve(np.transpose(A), a) tauct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3])) # ... and the soft valence density: nt = np.zeros(N) for f_n, s_n in zip(f_ln, s_ln): nt += np.dot(f_n, s_n**2) / (4 * pi) nt[1:] /= r[1:]**2 nt[0] = nt[1] nt += nct self.nt = nt # Calculate the shape function: x = r / rcutcomp gaussian = np.zeros(N) self.gamma = gamma = 10.0 gaussian[:gmax] = np.exp(-gamma * x[:gmax]**2) gt = 4 * (gamma / rcutcomp**2)**1.5 / sqrt(pi) * gaussian norm = np.dot(gt, dv) #print norm, norm-1 assert abs(norm - 1) < 1e-2 gt /= norm # Calculate smooth charge density: Nt = np.dot(nt, dv) rhot = nt - (Nt + charge / (4 * pi)) * gt t('Pseudo-electron charge', 4 * pi * Nt) vHt = np.zeros(N) hartree(0, rhot * r * dr, self.beta, self.N, vHt) vHt[1:] /= r[1:] vHt[0] = vHt[1] vXCt = np.zeros(N) extra_xc_data = {} if self.xc.type != 'GLLB': Exct = self.xc.calculate_spherical(self.rgd, nt.reshape((1, -1)), vXCt.reshape((1, -1))) else: Exct = self.xc.get_smooth_xc_potential_and_energy_1d(vXCt) # Calculate extra-stuff for non-local functionals self.xc.get_extra_setup_data(extra_xc_data) vt = vHt + vXCt # Construct zero potential: gc = 1 + int(rcutvbar * N / (rcutvbar + beta)) if vbar_type == 'f': assert lmax == 2 uf = np.zeros(N) l = 3 # Solve for all-electron f-state: eps = 0.0 shoot(uf, l, self.vr, eps, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gmax) uf *= 1.0 / uf[gc] # Fit smooth pseudo f-state polynomium: A = np.ones((4, 4)) A[:, 0] = 1.0 A[:, 1] = r[gc - 2:gc + 2]**2 A[:, 2] = A[:, 1]**2 A[:, 3] = A[:, 1] * A[:, 2] a = uf[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1) a0, a1, a2, a3 = solve(A, a) r1 = r[:gc] r2 = r1**2 rl1 = r1**(l + 1) y = a0 + r2 * (a1 + r2 * (a2 + r2 * a3)) sf = uf.copy() sf[:gc] = rl1 * y # From 0 to gc, use analytic formula for kinetic energy operator: r4 = r2**2 r6 = r4 * r2 enumerator = (a0 * l * (l + 1) + a1 * (l + 2) * (l + 3) * r2 + a2 * (l + 4) * (l + 5) * r4 + a3 * (l + 6) * (l + 7) * r6) denominator = a0 + a1 * r2 + a2 * r4 + a3 * r6 ekin_over_phit = -0.5 * (enumerator / denominator - l * (l + 1)) ekin_over_phit[1:] /= r2[1:] vbar = eps - vt vbar[:gc] -= ekin_over_phit vbar[0] = vbar[1] # Actually we can collect the terms into # a single fraction without poles, so as to avoid doing this, # but this is good enough # From gc to gmax, use finite-difference formula for kinetic # energy operator: vbar[gc:gmax] -= self.kin(l, sf)[gc:gmax] / sf[gc:gmax] vbar[gmax:] = 0.0 else: assert vbar_type == 'poly' A = np.ones((2, 2)) A[0] = 1.0 A[1] = r[gc - 1:gc + 1]**2 a = vt[gc - 1:gc + 1] a = solve(np.transpose(A), a) r2 = r**2 vbar = a[0] + r2 * a[1] - vt vbar[gc:] = 0.0 vt += vbar # Construct projector functions: for l, (e_n, s_n, q_n) in enumerate(zip(e_ln, s_ln, q_ln)): for e, s, q in zip(e_n, s_n, q_n): q[:] = self.kin(l, s) + (vt - e) * s q[gcutmax:] = 0.0 filter = Filter(r, dr, gcutfilter, hfilter).filter vbar = filter(vbar * r) # Calculate matrix elements: self.dK_lnn = dK_lnn = [] self.dH_lnn = dH_lnn = [] self.dO_lnn = dO_lnn = [] for l, (e_n, u_n, s_n, q_n) in enumerate(zip(e_ln, u_ln, s_ln, q_ln)): A_nn = np.inner(s_n, q_n * dr) # Do a LU decomposition of A: nn = len(e_n) L_nn = np.identity(nn, float) U_nn = A_nn.copy() # Keep all bound states normalized if sum([n > 0 for n in n_ln[l]]) <= 1: for i in range(nn): for j in range(i + 1, nn): L_nn[j, i] = 1.0 * U_nn[j, i] / U_nn[i, i] U_nn[j, :] -= U_nn[i, :] * L_nn[j, i] dO_nn = (np.inner(u_n, u_n * dr) - np.inner(s_n, s_n * dr)) e_nn = np.zeros((nn, nn)) e_nn.ravel()[::nn + 1] = e_n dH_nn = np.dot(dO_nn, e_nn) - A_nn q_n[:] = np.dot(inv(np.transpose(U_nn)), q_n) s_n[:] = np.dot(inv(L_nn), s_n) u_n[:] = np.dot(inv(L_nn), u_n) dO_nn = np.dot(np.dot(inv(L_nn), dO_nn), inv(np.transpose(L_nn))) dH_nn = np.dot(np.dot(inv(L_nn), dH_nn), inv(np.transpose(L_nn))) ku_n = [self.kin(l, u, e) for u, e in zip(u_n, e_n)] ks_n = [self.kin(l, s) for s in s_n] dK_nn = 0.5 * (np.inner(u_n, ku_n * dr) - np.inner(s_n, ks_n * dr)) dK_nn += np.transpose(dK_nn).copy() dK_lnn.append(dK_nn) dO_lnn.append(dO_nn) dH_lnn.append(dH_nn) for n, q in enumerate(q_n): q[:] = filter(q, l) * r**(l + 1) A_nn = np.inner(s_n, q_n * dr) q_n[:] = np.dot(inv(np.transpose(A_nn)), q_n) self.vt = vt self.vbar = vbar t('state eigenvalue norm') t('--------------------------------') for l, (n_n, f_n, e_n) in enumerate(zip(n_ln, f_ln, e_ln)): for n in range(len(e_n)): if n_n[n] > 0: f = '(%d)' % f_n[n] t('%d%s%-4s: %12.6f %12.6f' % (n_n[n], 'spdf'[l], f, e_n[n], np.dot(s_ln[l][n]**2, dr))) else: t('*%s : %12.6f' % ('spdf'[l], e_n[n])) t('--------------------------------') self.logd = {} if logderiv: ni = 300 self.elog = np.linspace(-5.0, 1.0, ni) # Calculate logarithmic derivatives: gld = gcutmax + 10 self.rlog = r[gld] assert gld < gmax t('Calculating logarithmic derivatives at r=%.3f' % r[gld]) t('(skip with [Ctrl-C])') try: u = np.zeros(N) for l in range(4): self.logd[l] = (np.empty(ni), np.empty(ni)) if l <= lmax: dO_nn = dO_lnn[l] dH_nn = dH_lnn[l] q_n = q_ln[l] fae = open(self.symbol + '.ae.ld.' + 'spdf'[l], 'w') fps = open(self.symbol + '.ps.ld.' + 'spdf'[l], 'w') for i, e in enumerate(self.elog): # All-electron logarithmic derivative: u[:] = 0.0 shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2, self.scalarrel, gmax=gld) dudr = 0.5 * (u[gld + 1] - u[gld - 1]) / dr[gld] ld = dudr / u[gld] - 1.0 / r[gld] print >> fae, e, ld self.logd[l][0][i] = ld # PAW logarithmic derivative: s = self.integrate(l, vt, e, gld) if l <= lmax: A_nn = dH_nn - e * dO_nn s_n = [ self.integrate(l, vt, e, gld, q) for q in q_n ] B_nn = np.inner(q_n, s_n * dr) a_n = np.dot(q_n, s * dr) B_nn = np.dot(A_nn, B_nn) B_nn.ravel()[::len(a_n) + 1] += 1.0 c_n = solve(B_nn, np.dot(A_nn, a_n)) s -= np.dot(c_n, s_n) dsdr = 0.5 * (s[gld + 1] - s[gld - 1]) / dr[gld] ld = dsdr / s[gld] - 1.0 / r[gld] print >> fps, e, ld self.logd[l][1][i] = ld except KeyboardInterrupt: pass self.write(nc, 'nc') self.write(nt, 'nt') self.write(nct, 'nct') self.write(vbar, 'vbar') self.write(vt, 'vt') self.write(tauc, 'tauc') self.write(tauct, 'tauct') for l, (n_n, f_n, u_n, s_n, q_n) in enumerate(zip(n_ln, f_ln, u_ln, s_ln, q_ln)): for n, f, u, s, q in zip(n_n, f_n, u_n, s_n, q_n): if n < 0: self.write(u, 'ae', n=n, l=l) self.write(s, 'ps', n=n, l=l) self.write(q, 'proj', n=n, l=l) # Test for ghost states: for h in [0.05]: self.diagonalize(h) self.vn_j = vn_j = [] self.vl_j = vl_j = [] self.vf_j = vf_j = [] self.ve_j = ve_j = [] self.vu_j = vu_j = [] self.vs_j = vs_j = [] self.vq_j = vq_j = [] j_ln = [[0 for f in f_n] for f_n in f_ln] j = 0 for l, n_n in enumerate(n_ln): for n, nn in enumerate(n_n): if nn > 0: vf_j.append(f_ln[l][n]) vn_j.append(nn) vl_j.append(l) ve_j.append(e_ln[l][n]) vu_j.append(u_ln[l][n]) vs_j.append(s_ln[l][n]) vq_j.append(q_ln[l][n]) j_ln[l][n] = j j += 1 for l, n_n in enumerate(n_ln): for n, nn in enumerate(n_n): if nn < 0: vf_j.append(0) vn_j.append(nn) vl_j.append(l) ve_j.append(e_ln[l][n]) vu_j.append(u_ln[l][n]) vs_j.append(s_ln[l][n]) vq_j.append(q_ln[l][n]) j_ln[l][n] = j j += 1 nj = j self.dK_jj = np.zeros((nj, nj)) for l, j_n in enumerate(j_ln): for n1, j1 in enumerate(j_n): for n2, j2 in enumerate(j_n): self.dK_jj[j1, j2] = self.dK_lnn[l][n1, n2] if exx: X_p = constructX(self) ExxC = atomic_exact_exchange(self, 'core-core') else: X_p = None ExxC = None sqrt4pi = sqrt(4 * pi) setup = SetupData(self.symbol, self.xc.name, self.name, readxml=False) def divide_by_r(x_g, l): r = self.r #for x_g, l in zip(x_jg, l_j): p = x_g.copy() p[1:] /= self.r[1:] # XXXXX go to higher order!!!!! if l == 0: #l_j[self.jcorehole] == 0: p[0] = (p[2] + (p[1] - p[2]) * (r[0] - r[2]) / (r[1] - r[2])) return p def divide_all_by_r(x_jg): return [divide_by_r(x_g, l) for x_g, l in zip(x_jg, vl_j)] setup.l_j = vl_j setup.n_j = vn_j setup.f_j = vf_j setup.eps_j = ve_j setup.rcut_j = [rcut_l[l] for l in vl_j] setup.nc_g = nc * sqrt4pi setup.nct_g = nct * sqrt4pi setup.nvt_g = (nt - nct) * sqrt4pi setup.e_kinetic_core = Ekincore setup.vbar_g = vbar * sqrt4pi setup.tauc_g = tauc * sqrt4pi setup.tauct_g = tauct * sqrt4pi setup.extra_xc_data = extra_xc_data setup.Z = Z setup.Nc = self.Nc setup.Nv = self.Nv setup.e_kinetic = self.Ekin setup.e_xc = self.Exc setup.e_electrostatic = self.Epot setup.e_total = self.Epot + self.Exc + self.Ekin setup.beta = self.beta setup.ng = self.N setup.rcgauss = self.rcutcomp / sqrt(self.gamma) setup.e_kin_jj = self.dK_jj setup.ExxC = ExxC setup.phi_jg = divide_all_by_r(vu_j) setup.phit_jg = divide_all_by_r(vs_j) setup.pt_jg = divide_all_by_r(vq_j) setup.X_p = X_p if self.jcorehole is not None: setup.has_corehole = True setup.lcorehole = l_j[self.jcorehole] # l_j or vl_j ????? XXX setup.ncorehole = n_j[self.jcorehole] setup.phicorehole_g = divide_by_r(self.u_j[self.jcorehole], setup.lcorehole) setup.core_hole_e = self.e_j[self.jcorehole] setup.core_hole_e_kin = self.Ekincorehole setup.fcorehole = self.fcorehole if self.ghost: raise RuntimeError('Ghost!') if self.scalarrel: reltype = 'scalar-relativistic' else: reltype = 'non-relativistic' attrs = [('type', reltype), ('name', 'gpaw-%s' % version)] data = 'Frozen core: ' + (self.core or 'none') setup.generatorattrs = attrs setup.generatordata = data self.id_j = [] for l, n in zip(vl_j, vn_j): if n > 0: id = '%s-%d%s' % (self.symbol, n, 'spdf'[l]) else: id = '%s-%s%d' % (self.symbol, 'spdf'[l], -n) self.id_j.append(id) setup.id_j = self.id_j if write_xml: setup.write_xml() return setup
def calculate(self): ESIC = 0 xc = self.paw.hamiltonian.xc assert xc.type == 'LDA' # Calculate the contribution from the core orbitals for a in self.paw.density.D_asp: setup = self.paw.density.setups[a] # TODO: Use XC which has been used to calculate the actual # calculation. # TODO: Loop over setups, not atoms. print('Atom core SIC for ', setup.symbol) print('%10s%10s%10s' % ('E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC')) g = Generator(setup.symbol, xcname='LDA', nofiles=True, txt=None) g.run(**parameters[setup.symbol]) njcore = g.njcore for f, l, e, u in zip(g.f_j[:njcore], g.l_j[:njcore], g.e_j[:njcore], g.u_j[:njcore]): # Calculate orbital density # NOTE: It's spherically symmetrized! #n = np.dot(self.f_j, assert l == 0, ('Not tested for l>0 core states') na = np.where(abs(u) < 1e-160, 0, u)**2 / (4 * pi) na[1:] /= g.r[1:]**2 na[0] = na[1] nb = np.zeros(g.N) v_sg = np.zeros((2, g.N)) e_g = np.zeros(g.N) vHr = np.zeros(g.N) Exc = xc.calculate_spherical(g.rgd, np.array([na, nb]), v_sg) hartree(0, na * g.r * g.dr, g.r, vHr) EHa = 2 * pi * np.dot(vHr * na * g.r, g.dr) print( ('%10.2f%10.2f%10.2f' % (Exc * Hartree, EHa * Hartree, -f * (EHa + Exc) * Hartree))) ESIC += -f * (EHa + Exc) sic = SIC(finegrid=True, coulomb_factor=1, xc_factor=1) sic.initialize(self.paw.density, self.paw.hamiltonian, self.paw.wfs) sic.set_positions(self.paw.atoms.get_scaled_positions()) print('Valence electron sic ') print('%10s%10s%10s%10s%10s%10s' % ('spin', 'k-point', 'band', 'E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC')) assert len( self.paw.wfs.kpt_u) == 1, ('Not tested for bulk calculations') for s, spin in sic.spin_s.items(): spin.initialize_orbitals() spin.update_optimal_states() spin.update_potentials() n = 0 for xc, c in zip(spin.exc_m, spin.ecoulomb_m): print(('%10i%10i%10i%10.2f%10.2f%10.2f' % (s, 0, n, -xc * Hartree, -c * Hartree, 2 * (xc + c) * Hartree))) n += 1 ESIC += spin.esic print('Total correction for self-interaction energy:') print('%10.2f eV' % (ESIC * Hartree)) print('New total energy:') total = (ESIC * Hartree + self.paw.get_potential_energy() + self.paw.get_reference_energy()) print('%10.2f eV' % total) return total
def constructX(gen): """Construct the X_p^a matrix for the given atom. The X_p^a matrix describes the valence-core interactions of the partial waves. """ # initialize attributes uv_j = gen.vu_j # soft valence states * r: lv_j = gen.vl_j # their repective l quantum numbers Nvi = 0 for l in lv_j: Nvi += 2 * l + 1 # total number of valence states (including m) # number of core and valence orbitals (j only, i.e. not m-number) Njcore = gen.njcore Njval = len(lv_j) # core states * r: uc_j = gen.u_j[:Njcore] r, dr, N, beta = gen.r, gen.dr, gen.N, gen.beta # potential times radius vr = np.zeros(N) # initialize X_ii matrix X_ii = np.zeros((Nvi, Nvi)) # make gaunt coeff. list lmax = max(gen.l_j[:Njcore] + gen.vl_j) gaunt = make_gaunt(lmax=lmax) # sum over core states for jc in range(Njcore): lc = gen.l_j[jc] # sum over first valence state index i1 = 0 for jv1 in range(Njval): lv1 = lv_j[jv1] # electron density 1 times radius times length element n1c = uv_j[jv1] * uc_j[jc] * dr n1c[1:] /= r[1:] # sum over second valence state index i2 = 0 for jv2 in range(Njval): lv2 = lv_j[jv2] # electron density 2 n2c = uv_j[jv2] * uc_j[jc] * dr n2c[1:] /= r[1:] # sum expansion in angular momenta for l in range(min(lv1, lv2) + lc + 1): # Int density * potential * r^2 * dr: hartree(l, n2c, r, vr) nv = np.dot(n1c, vr) # expansion coefficients A_mm = X_ii[i1:i1 + 2 * lv1 + 1, i2:i2 + 2 * lv2 + 1] for mc in range(2 * lc + 1): for m in range(2 * l + 1): G1c = gaunt[lv1**2:(lv1 + 1)**2, lc**2 + mc, l**2 + m] G2c = gaunt[lv2**2:(lv2 + 1)**2, lc**2 + mc, l**2 + m] A_mm += nv * np.outer(G1c, G2c) i2 += 2 * lv2 + 1 i1 += 2 * lv1 + 1 # pack X_ii matrix X_p = pack2(X_ii) return X_p
def run(self, use_restart_file=True): # beta g # r = ------, g = 0, 1, ..., N - 1 # N - g # # rN # g = -------- # beta + r t = self.text N = self.N beta = self.beta t(N, 'radial gridpoints.') self.rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N) g = np.arange(N, dtype=float) self.r = self.rgd.r_g self.dr = self.rgd.dr_g self.d2gdr2 = self.rgd.d2gdr2() # Number of orbitals: nj = len(self.n_j) # Radial wave functions multiplied by radius: self.u_j = np.zeros((nj, self.N)) # Effective potential multiplied by radius: self.vr = np.zeros(N) # Electron density: self.n = np.zeros(N) # Always spinpaired nspins=1 self.xc = XC(self.xcname) # Initialize for non-local functionals if self.xc.type == 'GLLB': self.xc.pass_stuff_1d(self) self.xc.initialize_1d() n_j = self.n_j l_j = self.l_j f_j = self.f_j e_j = self.e_j Z = self.Z # nuclear charge r = self.r # radial coordinate dr = self.dr # dr/dg n = self.n # electron density vr = self.vr # effective potential multiplied by r vHr = np.zeros(self.N) self.vXC = np.zeros(self.N) restartfile = '%s/%s.restart' % (tempdir, self.symbol) if self.xc.type == 'GLLB' or not use_restart_file: # Do not start from initial guess when doing # non local XC! # This is because we need wavefunctions as well # on the first iteration. fd = None else: try: fd = open(restartfile, 'rb') except IOError: fd = None else: try: n[:] = pickle.load(fd) except (ValueError, IndexError): fd = None else: norm = np.dot(n * r**2, dr) * 4 * pi if abs(norm - sum(f_j)) > 0.01: fd = None else: t('Using old density for initial guess.') n *= sum(f_j) / norm if fd is None: self.initialize_wave_functions() n[:] = self.calculate_density() bar = '|------------------------------------------------|' t(bar) niter = 0 nitermax = 117 qOK = log(1e-10) mix = 0.4 # orbital_free needs more iterations and coefficient if self.orbital_free: mix = 0.01 nitermax = 2000 e_j[0] /= self.tw_coeff if Z > 10: #help convergence for third row elements mix = 0.002 nitermax = 10000 vrold = None while True: # calculate hartree potential hartree(0, n * r * dr, r, vHr) # add potential from nuclear point charge (v = -Z / r) vHr -= Z # calculated exchange correlation potential and energy self.vXC[:] = 0.0 if self.xc.type == 'GLLB': # Update the potential to self.vXC an the energy to self.Exc Exc = self.xc.get_xc_potential_and_energy_1d(self.vXC) else: Exc = self.xc.calculate_spherical(self.rgd, n.reshape((1, -1)), self.vXC.reshape((1, -1))) # calculate new total Kohn-Sham effective potential and # admix with old version vr[:] = (vHr + self.vXC * r) if self.orbital_free: vr /= self.tw_coeff if niter > 0: vr[:] = mix * vr + (1 - mix) * vrold vrold = vr.copy() # solve Kohn-Sham equation and determine the density change self.solve() dn = self.calculate_density() - n n += dn # estimate error from the square of the density change integrated q = log(np.sum((r * dn)**2)) # print progress bar if niter == 0: q0 = q b0 = 0 else: b = int((q0 - q) / (q0 - qOK) * 50) if b > b0: self.txt.write(bar[b0:min(b, 50)]) self.txt.flush() b0 = b # check if converged and break loop if so if q < qOK: self.txt.write(bar[b0:]) self.txt.flush() break niter += 1 if niter > nitermax: raise RuntimeError('Did not converge!') tau = self.calculate_kinetic_energy_density() t() t('Converged in %d iteration%s.' % (niter, 's'[:niter != 1])) try: fd = open(restartfile, 'wb') except IOError: pass else: pickle.dump(n, fd) try: os.chmod(restartfile, 0o666) except OSError: pass Ekin = 0 for f, e in zip(f_j, e_j): Ekin += f * e e_coulomb = 2 * pi * np.dot(n * r * (vHr - Z), dr) Ekin += -4 * pi * np.dot(n * vr * r, dr) if self.orbital_free: # e and vr are not scaled back # instead Ekin is scaled for total energy (printed and inside setup) Ekin *= self.tw_coeff t() t('Lambda:{0}'.format(self.tw_coeff)) t('Correct eigenvalue:{0}'.format(e_j[0] * self.tw_coeff)) t() t() t('Energy contributions:') t('-------------------------') t('Kinetic: %+13.6f' % Ekin) t('XC: %+13.6f' % Exc) t('Potential: %+13.6f' % e_coulomb) t('-------------------------') t('Total: %+13.6f' % (Ekin + Exc + e_coulomb)) self.ETotal = Ekin + Exc + e_coulomb t() t('state eigenvalue ekin rmax') t('-----------------------------------------------') for m, l, f, e, u in zip(n_j, l_j, f_j, e_j, self.u_j): # Find kinetic energy: k = e - np.sum(( np.where(abs(u) < 1e-160, 0, u)**2 * # XXXNumeric! vr * dr)[1:] / r[1:]) # Find outermost maximum: g = self.N - 4 while u[g - 1] >= u[g]: g -= 1 x = r[g - 1:g + 2] y = u[g - 1:g + 2] A = np.transpose(np.array([x**i for i in range(3)])) c, b, a = np.linalg.solve(A, y) assert a < 0.0 rmax = -0.5 * b / a s = 'spdf'[l] t('%d%s^%-4.1f: %12.6f %12.6f %12.3f' % (m, s, f, e, k, rmax)) t('-----------------------------------------------') t('(units: Bohr and Hartree)') for m, l, u in zip(n_j, l_j, self.u_j): self.write(u, 'ae', n=m, l=l) self.write(n, 'n') self.write(vr, 'vr') self.write(vHr, 'vHr') self.write(self.vXC, 'vXC') self.write(tau, 'tau') self.Ekin = Ekin self.e_coulomb = e_coulomb self.Exc = Exc
def calculate(self): ESIC = 0 xc = self.paw.hamiltonian.xc assert xc.type == 'LDA' # Calculate the contribution from the core orbitals for a in self.paw.density.D_asp: setup = self.paw.density.setups[a] # TODO: Use XC which has been used to calculate the actual # calculation. # TODO: Loop over setups, not atoms. print('Atom core SIC for ', setup.symbol) print('%10s%10s%10s' % ('E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC')) g = Generator(setup.symbol, xcname='LDA', nofiles=True, txt=None) g.run(**parameters[setup.symbol]) njcore = g.njcore for f, l, e, u in zip(g.f_j[:njcore], g.l_j[:njcore], g.e_j[:njcore], g.u_j[:njcore]): # Calculate orbital density # NOTE: It's spherically symmetrized! #n = np.dot(self.f_j, assert l == 0, ('Not tested for l>0 core states') na = np.where(abs(u) < 1e-160, 0,u)**2 / (4 * pi) na[1:] /= g.r[1:]**2 na[0] = na[1] nb = np.zeros(g.N) v_sg = np.zeros((2, g.N)) e_g = np.zeros(g.N) vHr = np.zeros(g.N) Exc = xc.calculate_spherical(g.rgd, np.array([na, nb]), v_sg) hartree(0, na * g.r * g.dr, g.r, vHr) EHa = 2*pi*np.dot(vHr*na*g.r , g.dr) print(('%10.2f%10.2f%10.2f' % (Exc * Hartree, EHa * Hartree, -f*(EHa+Exc) * Hartree))) ESIC += -f*(EHa+Exc) sic = SIC(finegrid=True, coulomb_factor=1, xc_factor=1) sic.initialize(self.paw.density, self.paw.hamiltonian, self.paw.wfs) sic.set_positions(self.paw.atoms.get_scaled_positions()) print('Valence electron sic ') print('%10s%10s%10s%10s%10s%10s' % ('spin', 'k-point', 'band', 'E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC')) assert len(self.paw.wfs.kpt_u)==1, ('Not tested for bulk calculations') for s, spin in sic.spin_s.items(): spin.initialize_orbitals() spin.update_optimal_states() spin.update_potentials() n = 0 for xc, c in zip(spin.exc_m, spin.ecoulomb_m): print(('%10i%10i%10i%10.2f%10.2f%10.2f' % (s, 0, n, -xc * Hartree, -c * Hartree, 2 * (xc + c) * Hartree))) n += 1 ESIC += spin.esic print('Total correction for self-interaction energy:') print('%10.2f eV' % (ESIC * Hartree)) print('New total energy:') total = (ESIC * Hartree + self.paw.get_potential_energy() + self.paw.get_reference_energy()) print('%10.2f eV' % total) return total
def run(self, use_restart_file=True): # beta g # r = ------, g = 0, 1, ..., N - 1 # N - g # # rN # g = -------- # beta + r t = self.text N = self.N beta = self.beta t(N, 'radial gridpoints.') self.rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N) g = np.arange(N, dtype=float) self.r = self.rgd.r_g self.dr = self.rgd.dr_g self.d2gdr2 = self.rgd.d2gdr2() # Number of orbitals: nj = len(self.n_j) # Radial wave functions multiplied by radius: self.u_j = np.zeros((nj, self.N)) # Effective potential multiplied by radius: self.vr = np.zeros(N) # Electron density: self.n = np.zeros(N) # Always spinpaired nspins=1 self.xc = XC(self.xcname) # Initialize for non-local functionals if self.xc.type == 'GLLB': self.xc.pass_stuff_1d(self) self.xc.initialize_1d() n_j = self.n_j l_j = self.l_j f_j = self.f_j e_j = self.e_j Z = self.Z # nuclear charge r = self.r # radial coordinate dr = self.dr # dr/dg n = self.n # electron density vr = self.vr # effective potential multiplied by r vHr = np.zeros(self.N) self.vXC = np.zeros(self.N) restartfile = '%s/%s.restart' % (tempdir, self.symbol) if self.xc.type == 'GLLB' or not use_restart_file: # Do not start from initial guess when doing # non local XC! # This is because we need wavefunctions as well # on the first iteration. fd = None else: try: fd = open(restartfile, 'r') except IOError: fd = None else: try: n[:] = pickle.load(fd) except (ValueError, IndexError): fd = None else: norm = np.dot(n * r**2, dr) * 4 * pi if abs(norm - sum(f_j)) > 0.01: fd = None else: t('Using old density for initial guess.') n *= sum(f_j) / norm if fd is None: self.initialize_wave_functions() n[:] = self.calculate_density() bar = '|------------------------------------------------|' t(bar) niter = 0 nitermax = 117 qOK = log(1e-10) mix = 0.4 # orbital_free needs more iterations and coefficient if self.orbital_free: #qOK = log(1e-14) e_j[0] /= self.tf_coeff mix = 0.01 nitermax = 1000 vrold = None while True: # calculate hartree potential hartree(0, n * r * dr, r, vHr) # add potential from nuclear point charge (v = -Z / r) vHr -= Z # calculated exchange correlation potential and energy self.vXC[:] = 0.0 if self.xc.type == 'GLLB': # Update the potential to self.vXC an the energy to self.Exc Exc = self.xc.get_xc_potential_and_energy_1d(self.vXC) else: Exc = self.xc.calculate_spherical(self.rgd, n.reshape((1, -1)), self.vXC.reshape((1, -1))) # calculate new total Kohn-Sham effective potential and # admix with old version vr[:] = (vHr + self.vXC * r) / self.tf_coeff if niter > 0: vr[:] = mix * vr + (1 - mix) * vrold vrold = vr.copy() # solve Kohn-Sham equation and determine the density change self.solve() dn = self.calculate_density() - n n += dn # estimate error from the square of the density change integrated q = log(np.sum((r * dn)**2)) # print progress bar if niter == 0: q0 = q b0 = 0 else: b = int((q0 - q) / (q0 - qOK) * 50) if b > b0: self.txt.write(bar[b0:min(b, 50)]) self.txt.flush() b0 = b # check if converged and break loop if so if q < qOK: self.txt.write(bar[b0:]) self.txt.flush() break niter += 1 if niter > nitermax: raise RuntimeError('Did not converge!') tau = self.calculate_kinetic_energy_density() t() t('Converged in %d iteration%s.' % (niter, 's'[:niter != 1])) try: fd = open(restartfile, 'w') except IOError: pass else: pickle.dump(n, fd) try: os.chmod(restartfile, 0666) except OSError: pass Ekin = 0 if self.orbital_free: e_j[0] *= self.tf_coeff vr *= self.tf_coeff for f, e in zip(f_j, e_j): Ekin += f * e Epot = 2 * pi * np.dot(n * r * (vHr - Z), dr) Ekin += -4 * pi * np.dot(n * vr * r, dr) t() t('Energy contributions:') t('-------------------------') t('Kinetic: %+13.6f' % Ekin) t('XC: %+13.6f' % Exc) t('Potential: %+13.6f' % Epot) t('-------------------------') t('Total: %+13.6f' % (Ekin + Exc + Epot)) self.ETotal = Ekin + Exc + Epot t() t('state eigenvalue ekin rmax') t('-----------------------------------------------') for m, l, f, e, u in zip(n_j, l_j, f_j, e_j, self.u_j): # Find kinetic energy: k = e - np.sum((np.where(abs(u) < 1e-160, 0, u)**2 * # XXXNumeric! vr * dr)[1:] / r[1:]) # Find outermost maximum: g = self.N - 4 while u[g - 1] >= u[g]: g -= 1 x = r[g - 1:g + 2] y = u[g - 1:g + 2] A = np.transpose(np.array([x**i for i in range(3)])) c, b, a = np.linalg.solve(A, y) assert a < 0.0 rmax = -0.5 * b / a s = 'spdf'[l] t('%d%s^%-4.1f: %12.6f %12.6f %12.3f' % (m, s, f, e, k, rmax)) t('-----------------------------------------------') t('(units: Bohr and Hartree)') for m, l, u in zip(n_j, l_j, self.u_j): self.write(u, 'ae', n=m, l=l) self.write(n, 'n') self.write(vr, 'vr') self.write(vHr, 'vHr') self.write(self.vXC, 'vXC') self.write(tau, 'tau') self.Ekin = Ekin self.Epot = Epot self.Exc = Exc
def get_spherical_ks_potential(self,a): #self.paw.restore_state() print "XC:", self.paw.hamiltonian.xc.name assert self.paw.hamiltonian.xc.type == 'LDA' # If the calculation is just loaded, density needs to be interpolated if self.paw.density.nt_sg is None: print "Interpolating density" self.paw.density.interpolate() # Get xccorr for atom a setup = self.paw.density.setups[a] xccorr = setup.xc_correction # Get D_sp for atom a D_sp = self.paw.density.D_asp[a] # density a function of L and partial wave radial pair density coefficient D_sLq = np.inner(D_sp, xccorr.B_pqL.T) # The 'spherical' spherical harmonic Y0 = 1.0/sqrt(4*pi) # Generate cartesian fine grid xc-potential print "Generate cartesian fine grid xc-potential" gd = self.paw.density.finegd vxct_sg = gd.zeros(1) xc = self.paw.hamiltonian.xc xc.calculate(gd, self.paw.density.nt_sg, vxct_sg) # --------------------------------------------- # The Electrostatic potential # --------------------------------------------- # V_ES(r) = Vt_ES(r) - Vt^a(r) + V^a(r), where # Vt^a = P[ nt^a(r) + \sum Q_L g_L(r) ] # V^a = P[ -Z\delta(r) + n^a(r) ] # P = Poisson solution # --------------------------------------------- print "Evaluating ES Potential..." # Make sure that the calculation has ES potential # TODO if self.paw.hamiltonian.vHt_g == None: raise "Converge tha Hartree potential first." # Interpolate the smooth electrostatic potential from fine grid to radial grid radHt_g = self.grid_to_radial(a, gd, self.paw.hamiltonian.vHt_g) radHt_g *= xccorr.rgd.r_g print "D_sp", D_sp # Calculate the difference in density and pseudo density dn_g = (Y0 * np.dot(D_sLq[0, 0], (xccorr.n_qg - xccorr.nt_qg)) + xccorr.nc_g - xccorr.nct_g) # Add the compensation charge contribution dn_g -= Y0 * self.paw.density.Q_aL[a][0] * setup.g_lg[0] # Calculate the Hartree potential for this vHr = np.zeros((xccorr.ng,)) hartree(0, dn_g * xccorr.rgd.r_g * xccorr.rgd.dr_g, setup.beta, setup.ng, vHr) # Add the core potential contribution vHr -= setup.Z radHt_g += vHr # -------------------------------------------- # The XC potential # -------------------------------------------- # V_xc = Vt_xc(r) - Vt_xc^a(r) + V_xc^a(r) # -------------------------------------------- print "Evaluating xc potential" # Interpolate the smooth xc potential from fine grid to radial grid radvxct_g = self.grid_to_radial(a, gd, vxct_sg[0]) # Arrays for evaluating radial xc potential slice e_g = np.zeros((xccorr.ng,)) vxc_sg = np.zeros((len(D_sp), xccorr.ng)) for n, Y_L in enumerate(xccorr.Y_nL): n_sLg = np.dot(D_sLq, xccorr.n_qg) n_sLg[:, 0] += sqrt(4 * pi) * xccorr.nc_g vxc_sg[:] = 0.0 xc.calculate_radial(xccorr.rgd, n_sLg, Y_L, vxc_sg) radvxct_g += weight_n[n] * vxc_sg[0] nt_sLg = np.dot(D_sLq, xccorr.nt_qg) nt_sLg[:, 0] += sqrt(4 * pi) *xccorr.nct_g vxc_sg[:] = 0.0 xc.calculate_radial(xccorr.rgd, nt_sLg, Y_L, vxc_sg) radvxct_g -= weight_n[n] * vxc_sg[0] radvks_g = radvxct_g*xccorr.rgd.r_g + radHt_g return (xccorr.rgd.r_g, radvks_g)
def H(n_g, l): yrrdr_g = np.zeros(gcut2) nrdr_g = n_g * r_g * dr_g hartree(l, nrdr_g, beta, ng, yrrdr_g) yrrdr_g *= r_g * dr_g return yrrdr_g
def get_spherical_ks_potential(self, a): #self.paw.restore_state() print "XC:", self.paw.hamiltonian.xc.name assert self.paw.hamiltonian.xc.type == 'LDA' # If the calculation is just loaded, density needs to be interpolated if self.paw.density.nt_sg is None: print "Interpolating density" self.paw.density.interpolate() # Get xccorr for atom a setup = self.paw.density.setups[a] xccorr = setup.xc_correction # Get D_sp for atom a D_sp = self.paw.density.D_asp[a] # density a function of L and partial wave radial pair density coefficient D_sLq = np.inner(D_sp, xccorr.B_pqL.T) # The 'spherical' spherical harmonic Y0 = 1.0 / sqrt(4 * pi) # Generate cartesian fine grid xc-potential print "Generate cartesian fine grid xc-potential" gd = self.paw.density.finegd vxct_sg = gd.zeros(1) xc = self.paw.hamiltonian.xc xc.calculate(gd, self.paw.density.nt_sg, vxct_sg) # --------------------------------------------- # The Electrostatic potential # --------------------------------------------- # V_ES(r) = Vt_ES(r) - Vt^a(r) + V^a(r), where # Vt^a = P[ nt^a(r) + \sum Q_L g_L(r) ] # V^a = P[ -Z\delta(r) + n^a(r) ] # P = Poisson solution # --------------------------------------------- print "Evaluating ES Potential..." # Make sure that the calculation has ES potential # TODO if self.paw.hamiltonian.vHt_g == None: raise "Converge tha Hartree potential first." # Interpolate the smooth electrostatic potential from fine grid to radial grid radHt_g = self.grid_to_radial(a, gd, self.paw.hamiltonian.vHt_g) radHt_g *= xccorr.rgd.r_g print "D_sp", D_sp # Calculate the difference in density and pseudo density dn_g = (Y0 * np.dot(D_sLq[0, 0], (xccorr.n_qg - xccorr.nt_qg)) + xccorr.nc_g - xccorr.nct_g) # Add the compensation charge contribution dn_g -= Y0 * self.paw.density.Q_aL[a][0] * setup.g_lg[0] # Calculate the Hartree potential for this vHr = np.zeros((xccorr.ng, )) hartree(0, dn_g * xccorr.rgd.r_g * xccorr.rgd.dr_g, setup.beta, setup.ng, vHr) # Add the core potential contribution vHr -= setup.Z radHt_g += vHr # -------------------------------------------- # The XC potential # -------------------------------------------- # V_xc = Vt_xc(r) - Vt_xc^a(r) + V_xc^a(r) # -------------------------------------------- print "Evaluating xc potential" # Interpolate the smooth xc potential from fine grid to radial grid radvxct_g = self.grid_to_radial(a, gd, vxct_sg[0]) # Arrays for evaluating radial xc potential slice e_g = np.zeros((xccorr.ng, )) vxc_sg = np.zeros((len(D_sp), xccorr.ng)) for n, Y_L in enumerate(xccorr.Y_nL): n_sLg = np.dot(D_sLq, xccorr.n_qg) n_sLg[:, 0] += sqrt(4 * pi) * xccorr.nc_g vxc_sg[:] = 0.0 xc.calculate_radial(xccorr.rgd, n_sLg, Y_L, vxc_sg) radvxct_g += weight_n[n] * vxc_sg[0] nt_sLg = np.dot(D_sLq, xccorr.nt_qg) nt_sLg[:, 0] += sqrt(4 * pi) * xccorr.nct_g vxc_sg[:] = 0.0 xc.calculate_radial(xccorr.rgd, nt_sLg, Y_L, vxc_sg) radvxct_g -= weight_n[n] * vxc_sg[0] radvks_g = radvxct_g * xccorr.rgd.r_g + radHt_g return (xccorr.rgd.r_g, radvks_g)