def expand_hamiltonian_matrix(self): """Construct K_p from individual h_nn for each l.""" ni = sum([2 * l + 1 for l in self.l_j]) nj = len(self.l_j) H_ii = np.zeros((ni, ni)) if len(self.data['DIJ']) == 0: return pack2(H_ii) # Multiply by 4. # I think the factor of 4 compensates for the fact that the projectors # all had square norms of 4, but we brought them back down to 1 # because that's more sensible. H_jj = 4.0 * self.data['DIJ'].reshape((nj, nj)) m1start = 0 for j1, l1 in enumerate(self.l_j): j1 = self.jargs[j1] m1stop = m1start + 2 * l1 + 1 m2start = 0 for j2, l2 in enumerate(self.l_j): j2 = self.jargs[j2] m2stop = m2start + 2 * l2 + 1 if l1 == l2: dm = m1stop - m1start H_ii[m1start:m1stop, m2start:m2stop] = \ np.eye(dm) * H_jj[j1, j2] else: assert H_jj[j1, j2] == 0.0 m2start = m2stop m1start = m1stop return pack2(H_ii)
def expand_hamiltonian_matrix(self): """Construct K_p from individual h_nn for each l.""" ni = sum([2 * l + 1 for l in self.l_j]) H_ii = np.zeros((ni, ni)) # The H_ii used in gpaw is much larger and more general than the one # required for HGH pseudopotentials. This means a lot of the elements # must be assigned the same value. Not a performance issue though, # since these are small matrices M1start = 0 for n1, l1 in self.hghdata.nl_iter(): M1end = M1start + 2 * l1 + 1 M2start = 0 v = self.hghdata.v_l[l1] for n2, l2 in self.hghdata.nl_iter(): M2end = M2start + 2 * l2 + 1 if l1 == l2: h_nn = v.expand_hamiltonian_diagonal() H_mm = np.identity(M2end - M2start) * h_nn[n1, n2] H_ii[M1start:M1end, M2start:M2end] += H_mm M2start = M2end M1start = M1end K_p = pack2(H_ii) return K_p
def hubbard(setup, D_sp): nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl scale = setup.Hubs nl = np.where(np.equal(l_j, l))[0] nn = (2 * np.array(l_j) + 1)[0:nl[0]].sum() e_xc = 0.0 dH_sp = [] s = 0 for D_p in D_sp: N_mm, V = aoom(setup, unpack2(D_p), l, scale) N_mm = N_mm / 2 * nspins if nspins == 4: N_mm = N_mm / 2.0 if s == 0: Eorb = setup.HubU / 2. * (N_mm - 0.5 * np.dot(N_mm, N_mm)).trace() Vorb = setup.HubU / 2. * (np.eye(2 * l + 1) - N_mm) else: Eorb = setup.HubU / 2. * (-0.5 * np.dot(N_mm, N_mm)).trace() Vorb = -setup.HubU / 2. * N_mm else: Eorb = setup.HubU / 2. * (N_mm - np.dot(N_mm, N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2 * l + 1) - N_mm) e_xc += Eorb if nspins == 1: # add contribution of other spin manyfold e_xc += Eorb if len(nl) == 2: mm = (2 * np.array(l_j) + 1)[0:nl[1]].sum() V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[nn:nn + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb else: V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb dH_sp.append(pack2(V)) s += 1 return e_xc, dH_sp
def constructX(gen, gamma=0): """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 = gen.r, gen.dr, gen.N r2 = r**2 # 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) G_LLL = 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] n2c[1:] /= r2[1:] # sum expansion in angular momenta for l in range(min(lv1, lv2) + lc + 1): # Int density * potential * r^2 * dr: if gamma == 0: vr = gen.rgd.poisson(n2c, l) else: vr = gen.rgd.yukawa(n2c, l, gamma) 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 = G_LLL[lv1**2:(lv1 + 1)**2, lc**2 + mc, l**2 + m] G2c = G_LLL[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 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 make_paw_setup(self, tag=None): aea = self.aea setup = SetupData(aea.symbol, aea.xc.name, tag, readxml=False) nj = sum(len(waves) for waves in self.waves_l) setup.e_kin_jj = np.zeros((nj, nj)) setup.id_j = [] j1 = 0 for l, waves in enumerate(self.waves_l): ne = 0 for n, f, e, phi_g, phit_g, pt_g in zip(waves.n_n, waves.f_n, waves.e_n, waves.phi_ng, waves.phit_ng, waves.pt_ng): setup.append(n, l, f, e, waves.rcut, phi_g, phit_g, pt_g) if n == -1: ne += 1 id = '%s-%s%d' % (aea.symbol, 'spdf'[l], ne) else: id = '%s-%d%s' % (aea.symbol, n, 'spdf'[l]) setup.id_j.append(id) j2 = j1 + len(waves) setup.e_kin_jj[j1:j2, j1:j2] = waves.dekin_nn j1 = j2 setup.nc_g = self.nc_g * sqrt(4 * pi) setup.nct_g = self.nct_g * sqrt(4 * pi) setup.e_kinetic_core = self.ekincore setup.vbar_g = self.v0r_g * sqrt(4 * pi) setup.vbar_g[1:] /= self.rgd.r_g[1:] setup.vbar_g[0] = setup.vbar_g[1] setup.Z = aea.Z setup.Nc = self.ncore setup.Nv = self.nvalence setup.e_kinetic = aea.ekin setup.e_xc = aea.exc setup.e_electrostatic = aea.eH + aea.eZ setup.e_total = aea.exc + aea.ekin + aea.eH + aea.eZ setup.rgd = self.rgd setup.rcgauss = 1 / sqrt(self.alpha) self.calculate_exx_integrals() setup.ExxC = self.exxcc setup.X_p = pack2(self.exxcv_ii) setup.tauc_g = self.rgd.zeros() setup.tauct_g = self.rgd.zeros() #print 'no tau!!!!!!!!!!!' if self.aea.scalar_relativistic: reltype = 'scalar-relativistic' else: reltype = 'non-relativistic' attrs = [('type', reltype), ('version', 2), ('name', 'gpaw-%s' % version)] setup.generatorattrs = attrs setup.l0 = self.l0 setup.e0 = self.e0 setup.r0 = self.r0 setup.nderiv0 = self.nderiv0 return setup
def make_paw_setup(self, tag=None): aea = self.aea from gpaw.setup_data import SetupData setup = SetupData(aea.symbol, aea.xc.name, tag, readxml=False) setup.id_j = [] J = [] # new reordered j and i indices I = [] # Bound states: j = 0 i = 0 for l, waves in enumerate(self.waves_l): for n, f, e, phi_g, phit_g, pt_g in zip(waves.n_n, waves.f_n, waves.e_n, waves.phi_ng, waves.phit_ng, waves.pt_ng): if n != -1: setup.append(n, l, f, e, waves.rcut, phi_g, phit_g, pt_g) id = '%d%s' % (n, 'spdf'[l]) setup.id_j.append(id) J.append(j) I.extend(range(i, i + 2 * l + 1)) j += 1 i += 2 * l + 1 # Excited states: j = 0 i = 0 for l, waves in enumerate(self.waves_l): ne = 0 for n, f, e, phi_g, phit_g, pt_g in zip(waves.n_n, waves.f_n, waves.e_n, waves.phi_ng, waves.phit_ng, waves.pt_ng): if n == -1: setup.append(n, l, f, e, waves.rcut, phi_g, phit_g, pt_g) ne += 1 id = '%s%d' % ('spdf'[l], ne) setup.id_j.append(id) J.append(j) I.extend(range(i, i + 2 * l + 1)) j += 1 i += 2 * l + 1 nj = sum(len(waves) for waves in self.waves_l) e_kin_jj = np.zeros((nj, nj)) j1 = 0 for waves in self.waves_l: j2 = j1 + len(waves) e_kin_jj[j1:j2, j1:j2] = waves.dekin_nn j1 = j2 setup.e_kin_jj = e_kin_jj[J][:, J].copy() setup.nc_g = self.nc_g * sqrt(4 * pi) setup.nct_g = self.nct_g * sqrt(4 * pi) setup.e_kinetic_core = self.ekincore setup.vbar_g = self.v0r_g * sqrt(4 * pi) setup.vbar_g[1:] /= self.rgd.r_g[1:] setup.vbar_g[0] = setup.vbar_g[1] setup.Z = aea.Z setup.Nc = self.ncore setup.Nv = self.nvalence setup.e_kinetic = aea.ekin setup.e_xc = aea.exc setup.e_electrostatic = aea.eH + aea.eZ setup.e_total = aea.exc + aea.ekin + aea.eH + aea.eZ setup.rgd = self.rgd setup.rcgauss = 1 / sqrt(self.alpha) self.calculate_exx_integrals() setup.ExxC = self.exxcc setup.X_p = pack2(self.exxcv_ii[I][:, I]) setup.tauc_g = self.tauc_g * (4 * pi)**0.5 setup.tauct_g = self.tauct_g * (4 * pi)**0.5 if self.aea.scalar_relativistic: reltype = 'scalar-relativistic' else: reltype = 'non-relativistic' attrs = [('type', reltype), ('version', 2), ('name', 'gpaw-%s' % version)] setup.generatorattrs = attrs setup.l0 = self.l0 setup.e0 = 0.0 setup.r0 = self.r0 setup.nderiv0 = self.nderiv0 setup.basis = self.basis if self.core_hole: n, l, occ = self.core_hole phi_g = self.aea.channels[l].phi_ng[n - l - 1] setup.ncorehole = n setup.lcorehole = l setup.fcorehole = occ setup.phicorehole_g = phi_g setup.has_corehole = True return setup
def update(self, density): """Calculate effective potential. The XC-potential and the Hartree potential are evaluated on the fine grid, and the sum is then restricted to the coarse grid.""" self.timer.start("Hamiltonian") if self.vt_sg is None: self.timer.start("Initialize Hamiltonian") self.vt_sg = self.finegd.empty(self.ns) self.vHt_g = self.finegd.zeros() self.vt_sG = self.gd.empty(self.ns) self.poisson.initialize() self.timer.stop("Initialize Hamiltonian") Ekin, Epot, Ebar, Eext, Exc, W_aL = self.update_pseudo_potential(density) self.timer.start("Atomic") self.dH_asp = None # XXXX dH_asp = {} for a, D_sp in density.D_asp.items(): W_L = W_aL[a] setup = self.setups[a] D_p = D_sp[: self.nspins].sum(0) dH_p = setup.K_p + setup.M_p + setup.MB_p + 2.0 * np.dot(setup.M_pp, D_p) + np.dot(setup.Delta_pL, W_L) Ekin += np.dot(setup.K_p, D_p) + setup.Kc Ebar += setup.MB + np.dot(setup.MB_p, D_p) Epot += setup.M + np.dot(D_p, (setup.M_p + np.dot(setup.M_pp, D_p))) if self.vext is not None: vext = self.vext.get_taylor(spos_c=self.spos_ac[a, :]) # Tailor expansion to the zeroth order Eext += vext[0][0] * (sqrt(4 * pi) * density.Q_aL[a][0] + setup.Z) dH_p += vext[0][0] * sqrt(4 * pi) * setup.Delta_pL[:, 0] if len(vext) > 1: # Tailor expansion to the first order Eext += sqrt(4 * pi / 3) * np.dot(vext[1], density.Q_aL[a][1:4]) # there must be a better way XXXX Delta_p1 = np.array([setup.Delta_pL[:, 1], setup.Delta_pL[:, 2], setup.Delta_pL[:, 3]]) dH_p += sqrt(4 * pi / 3) * np.dot(vext[1], Delta_p1) dH_asp[a] = dH_sp = np.zeros_like(D_sp) if setup.HubU is not None: assert self.collinear nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl scale = setup.Hubs nl = np.where(np.equal(l_j, l))[0] nn = (2 * np.array(l_j) + 1)[0 : nl[0]].sum() for D_p, H_p in zip(D_sp, dH_asp[a]): [N_mm, V] = self.aoom(unpack2(D_p), a, l, scale) N_mm = N_mm / 2 * nspins Eorb = setup.HubU / 2.0 * (N_mm - np.dot(N_mm, N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2 * l + 1) - N_mm) Exc += Eorb if nspins == 1: # add contribution of other spin manyfold Exc += Eorb if len(nl) == 2: mm = (2 * np.array(l_j) + 1)[0 : nl[1]].sum() V[nn : nn + 2 * l + 1, nn : nn + 2 * l + 1] *= Vorb V[mm : mm + 2 * l + 1, nn : nn + 2 * l + 1] *= Vorb V[nn : nn + 2 * l + 1, mm : mm + 2 * l + 1] *= Vorb V[mm : mm + 2 * l + 1, mm : mm + 2 * l + 1] *= Vorb else: V[nn : nn + 2 * l + 1, nn : nn + 2 * l + 1] *= Vorb Htemp = unpack(H_p) Htemp += V H_p[:] = pack2(Htemp) dH_sp[: self.nspins] += dH_p if self.ref_dH_asp: dH_sp += self.ref_dH_asp[a] # We are not yet done with dH_sp; still need XC correction below Ddist_asp = self.dh_distributor.distribute(density.D_asp) dHdist_asp = {} Exca = 0.0 self.timer.start("XC Correction") for a, D_sp in Ddist_asp.items(): setup = self.setups[a] dH_sp = np.zeros_like(D_sp) Exca += self.xc.calculate_paw_correction(setup, D_sp, dH_sp, a=a) # XXX Exc are added on the "wrong" distribution; sum only works # when gd.comm and distribution comm are the same dHdist_asp[a] = dH_sp self.timer.stop("XC Correction") dHdist_asp = self.dh_distributor.collect(dHdist_asp) # Exca has contributions from all cores so modify it so it is # parallel in the same way as the other energies. Exca = self.world.sum(Exca) if self.gd.comm.rank == 0: Exc += Exca assert len(dHdist_asp) == len(self.atom_partition.my_indices) for a, D_sp in density.D_asp.items(): dH_sp = dH_asp[a] dH_sp += dHdist_asp[a] Ekin -= (D_sp * dH_sp).sum() # NCXXX self.dH_asp = dH_asp self.timer.stop("Atomic") # Make corrections due to non-local xc: # xcfunc = self.xc.xcfunc self.Enlxc = 0.0 # XXXxcfunc.get_non_local_energy() Ekin += self.xc.get_kinetic_energy_correction() / self.gd.comm.size energies = np.array([Ekin, Epot, Ebar, Eext, Exc]) self.timer.start("Communicate energies") self.gd.comm.sum(energies) # Make sure that all CPUs have the same energies self.world.broadcast(energies, 0) self.timer.stop("Communicate energies") (self.Ekin0, self.Epot, self.Ebar, self.Eext, self.Exc) = energies # self.Exc += self.Enlxc # self.Ekin0 += self.Enlkin self.timer.stop("Hamiltonian")
def update(self, density): """Calculate effective potential. The XC-potential and the Hartree potential are evaluated on the fine grid, and the sum is then restricted to the coarse grid.""" self.timer.start('Hamiltonian') if self.vt_sg is None: self.timer.start('Initialize Hamiltonian') self.vt_sg = self.finegd.empty(self.nspins) self.vHt_g = self.finegd.zeros() self.vt_sG = self.gd.empty(self.nspins) self.poisson.initialize() self.timer.stop('Initialize Hamiltonian') self.timer.start('vbar') Ebar = self.finegd.integrate(self.vbar_g, density.nt_g, global_integral=False) vt_g = self.vt_sg[0] vt_g[:] = self.vbar_g self.timer.stop('vbar') Eext = 0.0 if self.vext_g is not None: vt_g += self.vext_g.get_potential(self.finegd) Eext = self.finegd.integrate(vt_g, density.nt_g, global_integral=False) - Ebar if self.nspins == 2: self.vt_sg[1] = vt_g self.timer.start('XC 3D grid') Exc = self.xc.calculate(self.finegd, density.nt_sg, self.vt_sg) Exc /= self.gd.comm.size self.timer.stop('XC 3D grid') self.timer.start('Poisson') # npoisson is the number of iterations: self.npoisson = self.poisson.solve(self.vHt_g, density.rhot_g, charge=-density.charge) self.timer.stop('Poisson') self.timer.start('Hartree integrate/restrict') Epot = 0.5 * self.finegd.integrate(self.vHt_g, density.rhot_g, global_integral=False) Ekin = 0.0 for vt_g, vt_G, nt_G in zip(self.vt_sg, self.vt_sG, density.nt_sG): vt_g += self.vHt_g self.restrict(vt_g, vt_G) Ekin -= self.gd.integrate(vt_G, nt_G - density.nct_G, global_integral=False) self.timer.stop('Hartree integrate/restrict') # Calculate atomic hamiltonians: self.timer.start('Atomic') W_aL = {} for a in density.D_asp: W_aL[a] = np.empty((self.setups[a].lmax + 1)**2) density.ghat.integrate(self.vHt_g, W_aL) self.dH_asp = {} for a, D_sp in density.D_asp.items(): W_L = W_aL[a] setup = self.setups[a] D_p = D_sp.sum(0) dH_p = (setup.K_p + setup.M_p + setup.MB_p + 2.0 * np.dot(setup.M_pp, D_p) + np.dot(setup.Delta_pL, W_L)) Ekin += np.dot(setup.K_p, D_p) + setup.Kc Ebar += setup.MB + np.dot(setup.MB_p, D_p) Epot += setup.M + np.dot(D_p, (setup.M_p + np.dot(setup.M_pp, D_p))) if self.vext_g is not None: vext = self.vext_g.get_taylor(spos_c=self.spos_ac[a, :]) # Tailor expansion to the zeroth order Eext += vext[0][0] * (sqrt(4 * pi) * density.Q_aL[a][0] + setup.Z) dH_p += vext[0][0] * sqrt(4 * pi) * setup.Delta_pL[:, 0] if len(vext) > 1: # Tailor expansion to the first order Eext += sqrt(4 * pi / 3) * np.dot(vext[1], density.Q_aL[a][1:4]) # there must be a better way XXXX Delta_p1 = np.array([setup.Delta_pL[:, 1], setup.Delta_pL[:, 2], setup.Delta_pL[:, 3]]) dH_p += sqrt(4 * pi / 3) * np.dot(vext[1], Delta_p1) self.dH_asp[a] = dH_sp = np.zeros_like(D_sp) self.timer.start('XC Correction') Exc += setup.xc_correction.calculate(self.xc, D_sp, dH_sp, a) self.timer.stop('XC Correction') if setup.HubU is not None: nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl nl = np.where(np.equal(l_j,l))[0] nn = (2*np.array(l_j)+1)[0:nl[0]].sum() for D_p, H_p in zip(D_sp, self.dH_asp[a]): [N_mm,V] =self.aoom(unpack2(D_p),a,l) N_mm = N_mm / 2 * nspins Eorb = setup.HubU / 2. * (N_mm - np.dot(N_mm,N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2*l+1) - N_mm) Exc += Eorb if nspins == 1: # add contribution of other spin manyfold Exc += Eorb if len(nl)==2: mm = (2*np.array(l_j)+1)[0:nl[1]].sum() V[nn:nn+2*l+1,nn:nn+2*l+1] *= Vorb V[mm:mm+2*l+1,nn:nn+2*l+1] *= Vorb V[nn:nn+2*l+1,mm:mm+2*l+1] *= Vorb V[mm:mm+2*l+1,mm:mm+2*l+1] *= Vorb else: V[nn:nn+2*l+1,nn:nn+2*l+1] *= Vorb Htemp = unpack(H_p) Htemp += V H_p[:] = pack2(Htemp) dH_sp += dH_p Ekin -= (D_sp * dH_sp).sum() self.timer.stop('Atomic') # Make corrections due to non-local xc: #xcfunc = self.xc.xcfunc self.Enlxc = 0.0#XXXxcfunc.get_non_local_energy() Ekin += self.xc.get_kinetic_energy_correction() / self.gd.comm.size energies = np.array([Ekin, Epot, Ebar, Eext, Exc]) self.timer.start('Communicate energies') self.gd.comm.sum(energies) self.timer.stop('Communicate energies') (self.Ekin0, self.Epot, self.Ebar, self.Eext, self.Exc) = energies #self.Exc += self.Enlxc #self.Ekin0 += self.Enlkin self.timer.stop('Hamiltonian')
def update(self, density): """Calculate effective potential. The XC-potential and the Hartree potential are evaluated on the fine grid, and the sum is then restricted to the coarse grid.""" self.timer.start('Hamiltonian') if self.vt_sg is None: self.timer.start('Initialize Hamiltonian') self.vt_sg = self.finegd.empty(self.nspins * self.ncomp**2) self.vHt_g = self.finegd.zeros() self.vt_sG = self.gd.empty(self.nspins * self.ncomp**2) self.poisson.initialize() self.timer.stop('Initialize Hamiltonian') Ekin, Epot, Ebar, Eext, Exc, W_aL = \ self.update_pseudo_potential(density) self.timer.start('Atomic') self.dH_asp = {} for a, D_sp in density.D_asp.items(): W_L = W_aL[a] setup = self.setups[a] D_p = D_sp[:self.nspins].sum(0) dH_p = (setup.K_p + setup.M_p + setup.MB_p + 2.0 * np.dot(setup.M_pp, D_p) + np.dot(setup.Delta_pL, W_L)) Ekin += np.dot(setup.K_p, D_p) + setup.Kc Ebar += setup.MB + np.dot(setup.MB_p, D_p) Epot += setup.M + np.dot(D_p, (setup.M_p + np.dot(setup.M_pp, D_p))) if self.vext is not None: vext = self.vext.get_taylor(spos_c=self.spos_ac[a, :]) # Tailor expansion to the zeroth order Eext += vext[0][0] * (sqrt(4 * pi) * density.Q_aL[a][0] + setup.Z) dH_p += vext[0][0] * sqrt(4 * pi) * setup.Delta_pL[:, 0] if len(vext) > 1: # Tailor expansion to the first order Eext += sqrt(4 * pi / 3) * np.dot(vext[1], density.Q_aL[a][1:4]) # there must be a better way XXXX Delta_p1 = np.array([setup.Delta_pL[:, 1], setup.Delta_pL[:, 2], setup.Delta_pL[:, 3]]) dH_p += sqrt(4 * pi / 3) * np.dot(vext[1], Delta_p1) self.dH_asp[a] = dH_sp = np.zeros_like(D_sp) self.timer.start('XC Correction') Exc += self.xc.calculate_paw_correction(setup, D_sp, dH_sp, a=a) self.timer.stop('XC Correction') if setup.HubU is not None: assert self.collinear nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl scale = setup.Hubs nl = np.where(np.equal(l_j,l))[0] nn = (2*np.array(l_j)+1)[0:nl[0]].sum() for D_p, H_p in zip(D_sp, self.dH_asp[a]): [N_mm,V] =self.aoom(unpack2(D_p),a,l, scale) N_mm = N_mm / 2 * nspins Eorb = setup.HubU / 2. * (N_mm - np.dot(N_mm,N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2*l+1) - N_mm) Exc += Eorb if nspins == 1: # add contribution of other spin manyfold Exc += Eorb if len(nl)==2: mm = (2*np.array(l_j)+1)[0:nl[1]].sum() V[nn:nn+2*l+1,nn:nn+2*l+1] *= Vorb V[mm:mm+2*l+1,nn:nn+2*l+1] *= Vorb V[nn:nn+2*l+1,mm:mm+2*l+1] *= Vorb V[mm:mm+2*l+1,mm:mm+2*l+1] *= Vorb else: V[nn:nn+2*l+1,nn:nn+2*l+1] *= Vorb Htemp = unpack(H_p) Htemp += V H_p[:] = pack2(Htemp) dH_sp[:self.nspins] += dH_p Ekin -= (D_sp * dH_sp).sum() # NCXXX self.timer.stop('Atomic') # Make corrections due to non-local xc: #xcfunc = self.xc.xcfunc self.Enlxc = 0.0 # XXXxcfunc.get_non_local_energy() Ekin += self.xc.get_kinetic_energy_correction() / self.gd.comm.size energies = np.array([Ekin, Epot, Ebar, Eext, Exc]) self.timer.start('Communicate energies') self.gd.comm.sum(energies) # Make sure that all CPUs have the same energies self.world.broadcast(energies, 0) self.timer.stop('Communicate energies') (self.Ekin0, self.Epot, self.Ebar, self.Eext, self.Exc) = energies #self.Exc += self.Enlxc #self.Ekin0 += self.Enlkin self.timer.stop('Hamiltonian')
def update(self, density): """Calculate effective potential. The XC-potential and the Hartree potential are evaluated on the fine grid, and the sum is then restricted to the coarse grid.""" self.timer.start('Hamiltonian') if self.vt_sg is None: self.timer.start('Initialize Hamiltonian') self.vt_sg = self.finegd.empty(self.ns) self.vHt_g = self.finegd.zeros() self.vt_sG = self.gd.empty(self.ns) self.poisson.initialize() self.timer.stop('Initialize Hamiltonian') Ekin, Epot, Ebar, Eext, Exc, W_aL = \ self.update_pseudo_potential(density) self.timer.start('Atomic') self.dH_asp = None # XXXX dH_asp = {} for a, D_sp in density.D_asp.items(): W_L = W_aL[a] setup = self.setups[a] D_p = D_sp[:self.nspins].sum(0) dH_p = (setup.K_p + setup.M_p + setup.MB_p + 2.0 * np.dot(setup.M_pp, D_p) + np.dot(setup.Delta_pL, W_L)) Ekin += np.dot(setup.K_p, D_p) + setup.Kc Ebar += setup.MB + np.dot(setup.MB_p, D_p) Epot += setup.M + np.dot(D_p, (setup.M_p + np.dot(setup.M_pp, D_p))) if self.vext is not None: vext = self.vext.get_taylor(spos_c=self.spos_ac[a, :]) # Tailor expansion to the zeroth order Eext += vext[0][0] * (sqrt(4 * pi) * density.Q_aL[a][0] + setup.Z) dH_p += vext[0][0] * sqrt(4 * pi) * setup.Delta_pL[:, 0] if len(vext) > 1: # Tailor expansion to the first order Eext += sqrt(4 * pi / 3) * np.dot(vext[1], density.Q_aL[a][1:4]) # there must be a better way XXXX Delta_p1 = np.array([ setup.Delta_pL[:, 1], setup.Delta_pL[:, 2], setup.Delta_pL[:, 3] ]) dH_p += sqrt(4 * pi / 3) * np.dot(vext[1], Delta_p1) dH_asp[a] = dH_sp = np.zeros_like(D_sp) if setup.HubU is not None: assert self.collinear nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl scale = setup.Hubs nl = np.where(np.equal(l_j, l))[0] nn = (2 * np.array(l_j) + 1)[0:nl[0]].sum() for D_p, H_p in zip(D_sp, dH_asp[a]): [N_mm, V] = self.aoom(unpack2(D_p), a, l, scale) N_mm = N_mm / 2 * nspins Eorb = setup.HubU / 2. * (N_mm - np.dot(N_mm, N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2 * l + 1) - N_mm) Exc += Eorb if nspins == 1: # add contribution of other spin manyfold Exc += Eorb if len(nl) == 2: mm = (2 * np.array(l_j) + 1)[0:nl[1]].sum() V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[nn:nn + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb else: V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb Htemp = unpack(H_p) Htemp += V H_p[:] = pack2(Htemp) dH_sp[:self.nspins] += dH_p if self.ref_dH_asp: dH_sp += self.ref_dH_asp[a] # We are not yet done with dH_sp; still need XC correction below Ddist_asp = self.dh_distributor.distribute(density.D_asp) dHdist_asp = {} Exca = 0.0 self.timer.start('XC Correction') for a, D_sp in Ddist_asp.items(): setup = self.setups[a] dH_sp = np.zeros_like(D_sp) Exca += self.xc.calculate_paw_correction(setup, D_sp, dH_sp, a=a) # XXX Exc are added on the "wrong" distribution; sum only works # when gd.comm and distribution comm are the same dHdist_asp[a] = dH_sp self.timer.stop('XC Correction') dHdist_asp = self.dh_distributor.collect(dHdist_asp) # Exca has contributions from all cores so modify it so it is # parallel in the same way as the other energies. Exca = self.world.sum(Exca) if self.gd.comm.rank == 0: Exc += Exca assert len(dHdist_asp) == len(self.atom_partition.my_indices) for a, D_sp in density.D_asp.items(): dH_sp = dH_asp[a] dH_sp += dHdist_asp[a] Ekin -= (D_sp * dH_sp).sum() # NCXXX self.dH_asp = dH_asp self.timer.stop('Atomic') # Make corrections due to non-local xc: #xcfunc = self.xc.xcfunc self.Enlxc = 0.0 # XXXxcfunc.get_non_local_energy() Ekin += self.xc.get_kinetic_energy_correction() / self.gd.comm.size energies = np.array([Ekin, Epot, Ebar, Eext, Exc]) self.timer.start('Communicate energies') self.gd.comm.sum(energies) # Make sure that all CPUs have the same energies self.world.broadcast(energies, 0) self.timer.stop('Communicate energies') (self.Ekin0, self.Epot, self.Ebar, self.Eext, self.Exc) = energies #self.Exc += self.Enlxc #self.Ekin0 += self.Enlkin self.timer.stop('Hamiltonian')
def update_corrections(self, dens, W_aL): self.timer.start('Atomic') self.dH_asp = None # XXXX e_kinetic = 0.0 e_coulomb = 0.0 e_zero = 0.0 e_external = 0.0 e_xc = 0.0 D_asp = self.atomdist.to_work(dens.D_asp) dH_asp = self.setups.empty_atomic_matrix(self.nspins, D_asp.partition) for a, D_sp in D_asp.items(): W_L = W_aL[a] setup = self.setups[a] D_p = D_sp.sum(0) dH_p = (setup.K_p + setup.M_p + setup.MB_p + 2.0 * np.dot(setup.M_pp, D_p) + np.dot(setup.Delta_pL, W_L)) e_kinetic += np.dot(setup.K_p, D_p) + setup.Kc e_zero += setup.MB + np.dot(setup.MB_p, D_p) e_coulomb += setup.M + np.dot( D_p, (setup.M_p + np.dot(setup.M_pp, D_p))) dH_asp[a] = dH_sp = np.zeros_like(D_sp) if setup.HubU is not None: nspins = len(D_sp) l_j = setup.l_j l = setup.Hubl scale = setup.Hubs nl = np.where(np.equal(l_j, l))[0] nn = (2 * np.array(l_j) + 1)[0:nl[0]].sum() for D_p, H_p in zip(D_sp, dH_asp[a]): [N_mm, V] = self.aoom(unpack2(D_p), a, l, scale) N_mm = N_mm / 2 * nspins Eorb = setup.HubU / 2. * (N_mm - np.dot(N_mm, N_mm)).trace() Vorb = setup.HubU * (0.5 * np.eye(2 * l + 1) - N_mm) e_xc += Eorb if nspins == 1: # add contribution of other spin manyfold e_xc += Eorb if len(nl) == 2: mm = (2 * np.array(l_j) + 1)[0:nl[1]].sum() V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb V[nn:nn + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb V[mm:mm + 2 * l + 1, mm:mm + 2 * l + 1] *= Vorb else: V[nn:nn + 2 * l + 1, nn:nn + 2 * l + 1] *= Vorb Htemp = unpack(H_p) Htemp += V H_p[:] = pack2(Htemp) dH_sp += dH_p if self.ref_dH_asp: dH_sp += self.ref_dH_asp[a] self.timer.start('XC Correction') for a, D_sp in D_asp.items(): e_xc += self.xc.calculate_paw_correction(self.setups[a], D_sp, dH_asp[a], a=a) self.timer.stop('XC Correction') for a, D_sp in D_asp.items(): e_kinetic -= (D_sp * dH_asp[a]).sum() # NCXXX self.dH_asp = self.atomdist.from_work(dH_asp) self.timer.stop('Atomic') # Make corrections due to non-local xc: self.Enlxc = 0.0 # XXXxcfunc.get_non_local_energy() e_kinetic += self.xc.get_kinetic_energy_correction() / self.world.size return np.array([e_kinetic, e_coulomb, e_zero, e_external, e_xc])