def Coulomb_integral_kss(self, kss_ij, kss_kq, phit, rhot): # smooth part I = self.gd.integrate(rhot * phit) wfs = self.paw.wfs Pij_ani = wfs.kpt_u[kss_ij.spin].P_ani Pkq_ani = wfs.kpt_u[kss_kq.spin].P_ani # Add atomic corrections Ia = 0.0 for a, Pij_ni in Pij_ani.items(): Pi_i = Pij_ni[kss_ij.i] Pj_i = Pij_ni[kss_ij.j] Dij_ii = np.outer(Pi_i, Pj_i) Dij_p = pack(Dij_ii) Pk_i = Pkq_ani[a][kss_kq.i] Pq_i = Pkq_ani[a][kss_kq.j] Dkq_ii = np.outer(Pk_i, Pq_i) Dkq_p = pack(Dkq_ii) C_pp = wfs.setups[a].M_pp # ---- # 2 > P P C P P # ---- ip jr prst ks qt # prst Ia += 2.0*np.dot(Dkq_p, np.dot(C_pp, Dij_p)) I += self.gd.comm.sum(Ia) return I
def calculate_paw_fHXC_corrections(self, kss_ip, kss_jq, I_asp): i = kss_ip.occ_ind p = kss_ip.unocc_ind j = kss_jq.occ_ind q = kss_jq.unocc_ind Ia = 0.0 for a, P_ni in self.calc.wfs.kpt_u[kss_jq.spin_ind].P_ani.items(): Pip_ni = self.calc.wfs.kpt_u[kss_ip.spin_ind].P_ani[a] Dip_ii = np.outer(Pip_ni[i], Pip_ni[p]) Dip_p = pack(Dip_ii) Pjq_ni = self.calc.wfs.kpt_u[kss_jq.spin_ind].P_ani[a] Djq_ii = np.outer(Pjq_ni[j], Pjq_ni[q]) Djq_p = pack(Djq_ii) # Hartree part C_pp = self.calc.wfs.setups[a].M_pp # why factor of two here? # see appendix A of J. Chem. Phys. 128, 244101 (2008) # # 2 sum_prst P P C P P # ip jr prst ks qt Ia += self.fH_pre * 2.0 * np.dot(Djq_p, np.dot(C_pp, Dip_p)) # XC part, CHECK THIS JQ EVERWHERE!!! Ia += self.fxc_pre * np.dot(I_asp[a][kss_jq.spin_ind], Djq_p) return Ia
def symmetrize_atomic_density_matrices(self, D_asp): if len(self.kd.symmetry.op_scc) == 0: return if hasattr(D_asp, 'redistribute'): a_sa = self.kd.symmetry.a_sa D_asp.redistribute(self.atom_partition.as_serial()) for s in range(self.nspins): D_aii = [unpack2(D_asp[a][s]) for a in range(len(D_asp))] for a, D_ii in enumerate(D_aii): setup = self.setups[a] D_asp[a][s] = pack(setup.symmetrize(a, D_aii, a_sa)) D_asp.redistribute(self.atom_partition) else: all_D_asp = [] for a, setup in enumerate(self.setups): D_sp = D_asp.get(a) if D_sp is None: ni = setup.ni D_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) self.gd.comm.broadcast(D_sp, self.atom_partition.rank_a[a]) all_D_asp.append(D_sp) for s in range(self.nspins): D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp] for a, D_sp in D_asp.items(): setup = self.setups[a] D_sp[s] = pack(setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa))
def write(self, writer): """Writes response specific data to disc. During the writing process, the DeltaXC is calculated (if not yet calculated). """ if self.Dxc_vt_sG is None: self.calculate_delta_xc() wfs = self.wfs kpt_comm = wfs.kd.comm gd = wfs.gd nadm = 0 for setup in wfs.setups: ni = setup.ni nadm += ni * (ni + 1) // 2 # Not yet tested for parallerization # assert world.size == 1 shape = (wfs.nspins,) + tuple(gd.get_size_of_global_array()) # Write the pseudodensity on the coarse grid: writer.add_array('gllb_pseudo_response_potential', shape) if kpt_comm.rank == 0: for vt_G in self.vt_sG: writer.fill(gd.collect(vt_G) * Hartree) writer.add_array('gllb_dxc_pseudo_response_potential', shape) if kpt_comm.rank == 0: for Dxc_vt_G in self.Dxc_vt_sG: writer.fill(gd.collect(Dxc_vt_G) * (Hartree / Bohr)) def pack(X0_asp): X_asp = self.wfs.setups.empty_atomic_matrix( self.wfs.nspins, self.wfs.atom_partition) # XXX some of the provided X0_asp contain strangely duplicated # elements. Take only the minimal set: for a in X_asp: X_asp[a][:] = X0_asp[a] return pack_atomic_matrices(X_asp) writer.write(gllb_atomic_density_matrices=pack(self.D_asp)) writer.write(gllb_atomic_response_matrices=pack(self.Dresp_asp)) writer.write(gllb_dxc_atomic_density_matrices=pack(self.Dxc_D_asp)) writer.write( gllb_dxc_atomic_response_matrices=pack(self.Dxc_Dresp_asp))
def add_compensation_charges(self, nt_G, rhot_g): """Add compensation charges to input pair density, which is interpolated to the fine grid if needed.""" if self.finegrid: # interpolate the pair density to the fine grid self.density.interpolator.apply(nt_G, rhot_g) else: # copy values rhot_g[:] = nt_G # Determine the compensation charges for each nucleus Q_aL = {} for a, P_ni in self.P_ani.items(): assert P_ni.dtype == float # Generate density matrix P1_i = P_ni[self.n1] P2_i = P_ni[self.n2] D_ii = np.outer(P1_i.conj(), P2_i) # allowed to pack as used in the scalar product with # the symmetric array Delta_pL D_p = pack(D_ii, tolerance=1e30) # Determine compensation charge coefficients: Q_aL[a] = np.dot(D_p, self.density.setups[a].Delta_pL) # Add compensation charges if self.finegrid: self.density.ghat.add(rhot_g, Q_aL) else: self.density.Ghat.add(rhot_g, Q_aL)
def calculate_pair_density(self, n1, n2, kpt1, kpt2, ik1, ik2, bzq_index): psit1_G = self.kd.transform_wave_function(kpt1.psit_nG[n1], ik1) psit2_G = self.kd.transform_wave_function(kpt2.psit_nG[n2], ik2) nt_G = psit1_G.conj() * psit2_G s1 = self.kd.sym_k[ik1] s2 = self.kd.sym_k[ik2] t1 = self.kd.time_reversal_k[ik1] t2 = self.kd.time_reversal_k[ik2] k1_c = self.kd.ibzk_kc[kpt1.k] k2_c = self.kd.ibzk_kc[kpt2.k] Q_aL = {} for a in kpt1.P_ani.keys(): b1 = self.kd.symmetry.a_sa[s1, a] b2 = self.kd.symmetry.a_sa[s2, a] S1_c = np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s1]) - self.spos_ac[b1] S2_c = np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s2]) - self.spos_ac[b2] assert abs(S1_c.round() - S1_c).max() < 1e-13 assert abs(S2_c.round() - S2_c).max() < 1e-13 x1 = np.exp(2j * pi * np.dot(k1_c, S1_c)) x2 = np.exp(2j * pi * np.dot(k2_c, S2_c)) P1_i = np.dot(self.setups[a].R_sii[s1], kpt1.P_ani[b1][n1]) * x1 P2_i = np.dot(self.setups[a].R_sii[s2], kpt2.P_ani[b2][n2]) * x2 if t1: P1_i = P1_i.conj() if t2: P2_i = P2_i.conj() D_ii = np.outer(P1_i.conj(), P2_i) D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) self.ghat.add(nt_G, Q_aL, bzq_index) return nt_G
def raw_wignerseitz_LDOS(paw, a, spin): """Return a list of eigenvalues, and their weight on the specified atom""" wfs = paw.wfs assert wfs.dtype == float gd = wfs.gd atom_index = wignerseitz(gd, paw.atoms) w_k = wfs.weight_k nk = len(w_k) nb = wfs.bd.nbands energies = np.empty(nb * nk) weights = np.empty(nb * nk) x = 0 for k, w in enumerate(w_k): u = spin * nk + k energies[x:x + nb] = wfs.collect_eigenvalues(k=k, s=spin) for n, psit_G in enumerate(wfs.kpt_u[u].psit_nG): P_i = wfs.kpt_u[u].P_ani[a][n] P_p = pack(np.outer(P_i, P_i)) Delta_p = sqrt(4 * pi) * wfs.setups[a].Delta_pL[:, 0] weights[x + n] = w * (gd.integrate(abs( np.where(atom_index == a, psit_G, 0.0))**2) + np.dot(Delta_p, P_p)) x += nb return energies, weights
def raw_wignerseitz_LDOS(paw, a, spin): """Return a list of eigenvalues, and their weight on the specified atom""" wfs = paw.wfs assert wfs.dtype == float gd = wfs.gd atom_index = wignerseitz(gd, paw.atoms) w_k = wfs.kd.weight_k nk = len(w_k) nb = wfs.bd.nbands energies = np.empty(nb * nk) weights = np.empty(nb * nk) x = 0 for k, w in enumerate(w_k): u = spin * nk + k energies[x:x + nb] = wfs.collect_eigenvalues(k=k, s=spin) for n, psit_G in enumerate(wfs.kpt_u[u].psit_nG): P_i = wfs.kpt_u[u].P_ani[a][n] P_p = pack(np.outer(P_i, P_i)) Delta_p = sqrt(4 * pi) * wfs.setups[a].Delta_pL[:, 0] weights[x + n] = w * ( gd.integrate(abs(np.where(atom_index == a, psit_G, 0.0))**2) + np.dot(Delta_p, P_p)) x += nb return energies, weights
def with_compensation_charges(self, finegrid=False): """Get pair densisty including the compensation charges""" rhot = self.get(finegrid) # Determine the compensation charges for each nucleus Q_aL = {} for a, P_ni in self.P_ani.items(): # Generate density matrix Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] D_ii = np.outer(Pi_i, Pj_i) # allowed to pack as used in the scalar product with # the symmetric array Delta_pL D_p = pack(D_ii) # Determine compensation charge coefficients: Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) # Add compensation charges if finegrid: self.density.ghat.add(rhot, Q_aL) else: if not hasattr(self.density, 'Ghat'): self.density.Ghat = LFC(self.density.gd, [setup.ghat_l for setup in self.setups], integral=sqrt(4 * pi)) self.density.Ghat.set_positions(self.spos_ac) self.density.Ghat.add(rhot, Q_aL) return rhot
def with_compensation_charges(self, finegrid=False): """Get pair densisty including the compensation charges""" rhot = self.get(finegrid) # Determine the compensation charges for each nucleus Q_aL = {} for a, P_ni in self.P_ani.items(): # Generate density matrix Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] D_ii = np.outer(Pi_i, Pj_i) # allowed to pack as used in the scalar product with # the symmetric array Delta_pL D_p = pack(D_ii) # Determine compensation charge coefficients: Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) # Add compensation charges if finegrid: self.density.ghat.add(rhot, Q_aL) else: if not hasattr(self.density, 'Ghat'): self.density.Ghat = LFC( self.density.gd, [setup.ghat_l for setup in self.setups], integral=sqrt(4 * pi)) self.density.Ghat.set_positions(self.spos_ac) self.density.Ghat.add(rhot, Q_aL) return rhot
def initialize_density_matrix(self, f_si): nspins, nao = f_si.shape ni = self.ni D_sii = np.zeros((nspins, ni, ni)) D_sp = np.zeros((nspins, ni * (ni + 1) // 2)) nj = len(self.n_j) j = 0 i = 0 ib = 0 for phit in self.phit_j: l = phit.get_angular_momentum_number() # Skip projector functions not in basis set: while j < nj and self.l_j[j] != l: i += 2 * self.l_j[j] + 1 j += 1 if j == nj: break for m in range(2 * l + 1): D_sii[:, i + m, i + m] = f_si[:, ib + m] j += 1 i += 2 * l + 1 ib += 2 * l + 1 for s in range(nspins): D_sp[s] = pack(D_sii[s]) return D_sp
def initialize_density_matrix(self, f_si): nspins, nao = f_si.shape ni = self.ni D_sii = np.zeros((nspins, ni, ni)) D_sp = np.zeros((nspins, ni * (ni + 1) // 2)) nj = len(self.l_j) j = 0 i = 0 ib = 0 for phit in self.phit_j: l = phit.get_angular_momentum_number() # Skip functions not in basis set: while j < nj and self.l_j[j] != l: i += 2 * self.l_j[j] + 1 j += 1 if j == nj: break for m in range(2 * l + 1): D_sii[:, i + m, i + m] = f_si[:, ib + m] j += 1 i += 2 * l + 1 ib += 2 * l + 1 for s in range(nspins): D_sp[s] = pack(D_sii[s]) return D_sp
def get_orbital_density_matrix(self, a, kpt, n): """Add the nth band density from kpt to density matrix D_sp""" ni = self.setups[a].ni D_sii = np.zeros((self.nspins, ni, ni)) P_i = kpt.P_ani[a][n] D_sii[kpt.s] += np.outer(P_i.conj(), P_i).real D_sp = [pack(D_ii) for D_ii in D_sii] return D_sp
def calculate_delta_xc_perturbation(self): h**o, lumo = self.occupations.get_homo_lumo(self.wfs) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[0]) #print self.Dxc_vt_sG[0][0][0] nt_G = self.gd.empty() ne = self.nvalence # Number of electrons assert self.nspins == 1 lumo_n = ne // 2 eps_u = [] eps_un = np.zeros((len(self.kpt_u), len(self.kpt_u[0].psit_nG))) for u, kpt in enumerate(self.kpt_u): #print "K-Point index: ",u for n in range(len(kpt.psit_nG)): nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack(np.outer(P_ni[n].T.conj(), P_ni[n]).real) E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p) #print "Atom corrections", E*27.21 E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G * self.Dxc_vt_sG[0]) E += kpt.eps_n[lumo_n] #print "Old eigenvalue", kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21 eps_un[u][n] = E method2_lumo = min([eps_n[lumo_n] for eps_n in eps_un]) method2_lumo = -self.kpt_comm.max(-method2_lumo) method2_dxc = method2_lumo - lumo Ha = 27.2116 Ksgap *= Ha method1_dxc *= Ha method2_dxc *= Ha if world.rank is not 0: return (Ksgap, method2_dxc) print print "\Delta XC calulation" print "-----------------------------------------------" print "| Method | KS-Gap | \Delta XC | QP-Gap |" print "-----------------------------------------------" print "| Averaging | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap + method1_dxc) print "| Lumo pert. | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap + method2_dxc) print "-----------------------------------------------" print return (Ksgap, method2_dxc)
def calculate_delta_xc_perturbation_spin(self, s=0): h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[s]) nt_G = self.gd.empty() # Find the lumo-orbital of this spin sign = 1 - s * 2 lumo_n = (self.occupations.nvalence + sign * self.occupations.magmom) // 2 gaps = [1000.0] for u, kpt in enumerate(self.kpt_u): if kpt.s == s: nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, lumo_n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack( np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real) print( "self.integrate_sphere DOES NOT SUPPORT SPIN POLARIZED? atc_response.py" ) E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p) E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G * self.Dxc_vt_sG[s]) E += kpt.eps_n[lumo_n] gaps.append(E - lumo) #print "Old eigenvalue", kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21 #eps_un[u][n] = E method2_dxc = -self.kpt_comm.max(-min(gaps)) Ha = 27.2116 Ksgap *= Ha method1_dxc *= Ha method2_dxc *= Ha if world.rank is not 0: return (Ksgap, method2_dxc) print() print("\Delta XC calulation") print("-----------------------------------------------") print("| Method | KS-Gap | \Delta XC | QP-Gap |") print("-----------------------------------------------") print("| Averaging | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap + method1_dxc)) print("| Lumo pert. | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap + method2_dxc)) print("-----------------------------------------------") print() return (Ksgap, method2_dxc)
def calculate_delta_xc_perturbation(self): h**o, lumo = self.occupations.get_homo_lumo(self.wfs) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[0]) #print self.Dxc_vt_sG[0][0][0] nt_G = self.gd.empty() ne = self.nvalence # Number of electrons assert self.nspins == 1 lumo_n = ne // 2 eps_u =[] eps_un = np.zeros((len(self.kpt_u),len(self.kpt_u[0].psit_nG))) for u, kpt in enumerate(self.kpt_u): #print "K-Point index: ",u for n in range(len(kpt.psit_nG)): nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack(np.outer(P_ni[n].T.conj(), P_ni[n]).real) E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p) #print "Atom corrections", E*27.21 E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G*self.Dxc_vt_sG[0]) E += kpt.eps_n[lumo_n] #print "Old eigenvalue", kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21 eps_un[u][n] = E method2_lumo = min([ eps_n[lumo_n] for eps_n in eps_un]) method2_lumo = -self.kpt_comm.max(-method2_lumo) method2_dxc = method2_lumo-lumo Ha = 27.2116 Ksgap *= Ha method1_dxc *= Ha method2_dxc *= Ha if world.rank is not 0: return (Ksgap, method2_dxc) print print "\Delta XC calulation" print "-----------------------------------------------" print "| Method | KS-Gap | \Delta XC | QP-Gap |" print "-----------------------------------------------" print "| Averaging | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc) print "| Lumo pert. | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc) print "-----------------------------------------------" print return (Ksgap, method2_dxc)
def calculate_delta_xc_perturbation_spin(self, s=0): h**o, lumo = self.wfs.get_homo_lumo(s) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[s]) nt_G = self.gd.empty() # Find the lumo-orbital of this spin sign = 1 - s * 2 lumo_n = int((self.wfs.nvalence + sign * self.occupations.magmom) // 2) gaps = [1000.0] for u, kpt in enumerate(self.kpt_u): if kpt.s == s: nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, lumo_n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack( np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real) E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p, spin=s) E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G * self.Dxc_vt_sG[s]) E += kpt.eps_n[lumo_n] gaps.append(E - lumo) method2_dxc = -self.kpt_comm.max(-min(gaps)) Ha = 27.2116 Ksgap *= Ha method1_dxc *= Ha method2_dxc *= Ha if world.rank is not 0: return (Ksgap, method2_dxc) if 0: # TODO print properly, not to stdout! print() print('\Delta XC calulation') print('-----------------------------------------------') print('| Method | KS-Gap | \Delta XC | QP-Gap |') print('-----------------------------------------------') print('| Averaging | %7.2f | %9.2f | %7.2f |' % (Ksgap, method1_dxc, Ksgap + method1_dxc)) print('| Lumo pert. | %7.2f | %9.2f | %7.2f |' % (Ksgap, method2_dxc, Ksgap + method2_dxc)) print('-----------------------------------------------') print() return (Ksgap, method2_dxc)
def symmetrize_atomic_density_matrices(self, D_asp): if len(self.kd.symmetry.op_scc) == 0: return a_sa = self.kd.symmetry.a_sa D_asp.redistribute(self.atom_partition.as_serial()) for s in range(self.nspins): D_aii = [unpack2(D_asp[a][s]) for a in range(len(D_asp))] for a, D_ii in enumerate(D_aii): setup = self.setups[a] D_asp[a][s] = pack(setup.symmetrize(a, D_aii, a_sa)) D_asp.redistribute(self.atom_partition)
def calculate_delta_xc_perturbation_spin(self, s=0): h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[s]) nt_G = self.gd.empty() # Find the lumo-orbital of this spin sign = 1 - s * 2 lumo_n = (self.occupations.nvalence + sign * self.occupations.magmom) // 2 gaps = [ 1000.0 ] for u, kpt in enumerate(self.kpt_u): if kpt.s == s: nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, lumo_n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack(np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real) print("self.integrate_sphere DOES NOT SUPPORT SPIN POLARIZED? atc_response.py") E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p) E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G*self.Dxc_vt_sG[s]) E += kpt.eps_n[lumo_n] gaps.append(E-lumo) #print "Old eigenvalue", kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21 #eps_un[u][n] = E method2_dxc = -self.kpt_comm.max(-min(gaps)) Ha = 27.2116 Ksgap *= Ha method1_dxc *= Ha method2_dxc *= Ha if world.rank is not 0: return (Ksgap, method2_dxc) print() print("\Delta XC calulation") print("-----------------------------------------------") print("| Method | KS-Gap | \Delta XC | QP-Gap |") print("-----------------------------------------------") print("| Averaging | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc)) print("| Lumo pert. | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc)) print("-----------------------------------------------") print() return (Ksgap, method2_dxc)
def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): """Calculate atomic density matrices from projections with custom occupation f_un.""" # Varying f_n used in calculation of response part of GLLB-potential for a, D_sp in D_asp.items(): ni = self.setups[a].ni D_sii = np.zeros((self.nspins, ni, ni)) for f_n, kpt in zip(f_un, self.kpt_u): self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a, f_n) D_sp[:] = [pack(D_ii) for D_ii in D_sii] self.band_comm.sum(D_sp) self.kpt_comm.sum(D_sp) self.symmetrize_atomic_density_matrices(D_asp)
def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): """Calculate atomic density matrices from projections with custom occupation f_un.""" # Varying f_n used in calculation of response part of GLLB-potential for a, D_sp in D_asp.items(): ni = self.setups[a].ni D_sii = np.zeros((len(D_sp), ni, ni)) for f_n, kpt in zip(f_un, self.kpt_u): self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a, f_n) D_sp[:] = [pack(D_ii) for D_ii in D_sii] self.band_comm.sum(D_sp) self.kpt_comm.sum(D_sp) self.symmetrize_atomic_density_matrices(D_asp)
def make_optimized(qstart, qend): g_qG = np.zeros((qend - qstart,) + w_wG.shape[1:], float) P_aqp = {} for a, P_wi in P_awi.items(): ni = P_wi.shape[1] nii = ni * (ni + 1) // 2 P_aqp[a] = np.zeros((qend - qstart, nii), float) for w1, w1_G in enumerate(w_wG): U = Uisq_iqj[w1, qstart: qend].copy() gemm(1., w1_G * w_wG, U, 1.0, g_qG) for a, P_wi in P_awi.items(): P_wp = np.array([pack(np.outer(P_wi[w1], P_wi[w2])) for w2 in range(Ni)]) gemm(1., P_wp, U, 1.0, P_aqp[a]) return g_qG, P_aqp
def symmetrize_atomic_density_matrices(self, D_asp): if len(self.kd.symmetry.op_scc) > 1: all_D_asp = [] for a, setup in enumerate(self.setups): D_sp = D_asp.get(a) if D_sp is None: ni = setup.ni D_sp = np.empty((self.ns, ni * (ni + 1) // 2)) self.gd.comm.broadcast(D_sp, self.rank_a[a]) all_D_asp.append(D_sp) for s in range(self.nspins): D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp] for a, D_sp in D_asp.items(): setup = self.setups[a] D_sp[s] = pack(setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa))
def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): """Calculate atomic density matrices from projections with custom occupation f_un.""" # Parameter check (if user accidentally passes f_n instead of f_un) if f_un[0] is not None: # special case for transport calculations... assert isinstance(f_un[0], np.ndarray) # Varying f_n used in calculation of response part of GLLB-potential for a, D_sp in D_asp.items(): ni = self.setups[a].ni D_sii = np.zeros((len(D_sp), ni, ni)) for f_n, kpt in zip(f_un, self.kpt_u): self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a, f_n) D_sp[:] = [pack(D_ii) for D_ii in D_sii] self.kptband_comm.sum(D_sp) self.symmetrize_atomic_density_matrices(D_asp)
def expand_wave_function(self, psit_G, u, n): """Get the weights of wave function in Wigner-Seitz cells around the atoms. The spin-k-point index u and band number n are needed for the augmentation sphere corrections.""" assert psit_G.dtype == float # smooth part weigths = self.expand(psit_G**2) # add augmentation sphere corrections for a, nucleus in enumerate(self.atoms): P_i = nucleus.P_uni[u, n] P_p = pack(np.outer(P_i, P_i)) Delta_p = sqrt(4 * pi) * nucleus.setup.Delta_pL[:, 0] weigths[a] += np.dot(Delta_p, P_p) return weigths
def symmetrize_atomic_density_matrices(self, D_asp): if len(self.kd.symmetry.op_scc) > 1: all_D_asp = [] for a, setup in enumerate(self.setups): D_sp = D_asp.get(a) if D_sp is None: ni = setup.ni D_sp = np.empty((self.ns, ni * (ni + 1) // 2)) self.gd.comm.broadcast(D_sp, self.rank_a[a]) all_D_asp.append(D_sp) for s in range(self.nspins): D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp] for a, D_sp in D_asp.items(): setup = self.setups[a] D_sp[s] = pack( setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa))
def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): """Calculate atomic density matrices from projections with custom occupation f_un.""" # Parameter check (if user accidentally passes f_n instead of f_un) if f_un[0] is not None: # special case for transport calculations... assert isinstance(f_un[0], np.ndarray) # Varying f_n used in calculation of response part of GLLB-potential for a, D_sp in D_asp.items(): ni = self.setups[a].ni D_sii = np.zeros((len(D_sp), ni, ni)) for f_n, kpt in zip(f_un, self.kpt_u): self.calculate_atomic_density_matrices_k_point( D_sii, kpt, a, f_n) D_sp[:] = [pack(D_ii) for D_ii in D_sii] self.kptband_comm.sum(D_sp) self.symmetrize_atomic_density_matrices(D_asp)
def calculate_delta_xc_perturbation_spin(self, s=0): h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s) Ksgap = lumo - h**o # Calculate average of lumo reference response potential method1_dxc = np.average(self.Dxc_vt_sG[s]) nt_G = self.gd.empty() epsilon = 1e-2 gaps = [ 1000.0 ] for u, kpt in enumerate(self.kpt_u): if kpt.s == s: lumo_n = np.flatnonzero(kpt.f_n/kpt.weight <= epsilon)[0] nt_G[:] = 0.0 self.wfs.add_orbital_density(nt_G, kpt, lumo_n) E = 0.0 for a in self.density.D_asp: D_sp = self.Dxc_D_asp[a] Dresp_sp = self.Dxc_Dresp_asp[a] P_ni = kpt.P_ani[a] Dwf_p = pack(np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real) E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p) E = self.grid_comm.sum(E) E += self.gd.integrate(nt_G*self.Dxc_vt_sG[s]) E += kpt.eps_n[lumo_n] gaps.append(E-lumo) method2_dxc = self.kpt_comm.min(min(gaps)) Ksgap *= Hartree method1_dxc *= Hartree method2_dxc *= Hartree if world.rank is not 0: return (Ksgap, method2_dxc) print print "\Delta XC calulation" print "-----------------------------------------------" print "| Method | KS-Gap | \Delta XC | QP-Gap |" print "-----------------------------------------------" print "| Averaging | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc) print "| Lumo pert. | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc) print "-----------------------------------------------" print return (Ksgap, method2_dxc)
def calculate_pair_density(self, n1, n2, kpt1, kpt2, q, invert): if invert: nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2].conj() else: nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2] Q_aL = {} for a, P1_ni in kpt1.P_ani.items(): P1_i = P1_ni[n1] P2_i = kpt2.P_ani[a][n2] if invert: D_ii = np.outer(P1_i.conj(), P2_i.conj()) else: D_ii = np.outer(P1_i.conj(), P2_i) D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) self.ghat.add(nt_G, Q_aL, q) return nt_G
def calculate_pair_density(self, n1, n2, kpt1, kpt2, q, k, eik1r_R, eik2r_R, eiqr_R, ibz2): if isinstance(self.wfs, PWWaveFunctions): psit1_R = self.wfs.pd.ifft(kpt1.psit_nG[n1]) * eik1r_R psit2_R = self.wfs.pd.ifft(kpt2.psit_nG[n2]) * eik2r_R else: psit1_R = kpt1.psit_nG[n1] psit2_R = kpt2.psit_nG[n2] if ibz2: psit2_R = psit2_R else: psit2_R = np.asarray(self.kd.transform_wave_function(psit2_R, k), complex) nt_R = psit1_R.conj() * psit2_R s = self.kd.sym_k[k] time_reversal = self.kd.time_reversal_k[k] k2_c = self.kd.ibzk_kc[kpt2.k] Q_aL = {} for a, P1_ni in kpt1.P_ani.items(): P1_i = P1_ni[n1] b = self.kd.symmetry.a_sa[s, a] S_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s]) - self.spos_ac[b]) assert abs(S_c.round() - S_c).max() < 1e-13 x = np.exp(2j * pi * np.dot(k2_c, S_c)) P2_i = np.dot(self.setups[a].R_sii[s], kpt2.P_ani[b][n2]) * x if time_reversal: P2_i = P2_i.conj() if ibz2: P2_i = kpt2.P_ani[a][n2] D_ii = np.outer(P1_i.conj(), P2_i) D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) self.ghat.add(nt_R, Q_aL, q) return nt_R / eiqr_R
def calculate_pair_density(self, n1, n2, psit_nG, P_ani): Q_aL = {} for a, P_ni in P_ani.items(): P1_i = P_ni[n1] P2_i = P_ni[n2] D_ii = np.outer(P1_i, P2_i.conj()).real D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) nt_G = psit_nG[n1] * psit_nG[n2] if self.finegd is self.gd: nt_g = nt_G else: nt_g = self.finegd.empty() self.interpolator.apply(nt_G, nt_g) rhot_g = nt_g.copy() self.ghat.add(rhot_g, Q_aL) return nt_G, rhot_g
def apply_oper(self, obj, sym, cart_rot, atom_deperm): from gpaw.utilities import pack, unpack2 a_a = self.symmetry.a_sa[sym] assert ( a_a == atom_deperm).all(), "mismatched oper order or something?" # permute the 'a' axis (atoms in the dict) obj = super().apply_oper(obj, sym, cart_rot, atom_deperm) # and now the 'p' axis dH_asp = obj for a in range(len(dH_asp)): R_ii = self.symmetry.R_asii[a][sym] for s in range(self.nspins): dH_p = dH_asp[a][s] dH_ii = unpack2(dH_p) tmp_ii = R_ii @ dH_ii @ R_ii.T tmp_p = pack(tmp_ii) dH_asp[a][s][...] = tmp_p return dH_asp
def calculate_density(self, m): # pseudo density nt_G = self.phit_mG[m]**2 if self.finegd is self.gd: nt_g = nt_G else: nt_g = self.finegd.empty() self.interpolator.apply(nt_G, nt_g) # normalize single-particle density nt_g *= self.gd.integrate(nt_G) / self.finegd.integrate(nt_g) # PAW corrections Q_aL = {} D_ap = {} for a, P_mi in self.P_ami.items(): P_i = P_mi[m] D_ii = np.outer(P_i, P_i.conj()).real D_ap[a] = D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) return nt_g, Q_aL, D_ap
def calculate_density(self, m): # # pseudo density nt_G = self.phit_mG[m]**2 if self.finegd is self.gd: nt_g = nt_G else: nt_g = self.finegd.empty() self.interpolator.apply(nt_G, nt_g) # normalize single-particle density nt_g *= self.gd.integrate(nt_G) / self.finegd.integrate(nt_g) # PAW corrections Q_aL = {} D_ap = {} for a, P_mi in self.P_ami.items(): P_i = P_mi[m] D_ii = np.outer(P_i, P_i.conj()).real D_ap[a] = D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) return nt_g, Q_aL, D_ap
def get_density(rho_MM, wfs, density, density_type='comp', u=0): rho_G = density.gd.zeros() kpt = wfs.kpt_u[u] assert kpt.q == 0 rho_MM = rho_MM.astype(wfs.dtype) wfs.basis_functions.construct_density(rho_MM, rho_G, kpt.q) # Uncomment this if you want to add the static part # rho_G += density.nct_G if density_type == 'pseudocoarse': return rho_G rho_g = density.finegd.zeros() density.distribute_and_interpolate(rho_G, rho_g) rho_G = None if density_type == 'pseudo': return rho_g if density_type == 'comp': D_asp = density.atom_partition.arraydict(density.D_asp.shapes_a) Q_aL = {} for a, D_sp in D_asp.items(): P_Mi = wfs.P_aqMi[a][kpt.q] assert np.max(np.absolute(P_Mi.imag)) == 0 P_Mi = P_Mi.real assert P_Mi.dtype == float D_ii = np.dot(np.dot(P_Mi.T.conj(), rho_MM), P_Mi) D_sp[:] = pack(D_ii)[np.newaxis, :] Q_aL[a] = np.dot(D_sp.sum(axis=0), wfs.setups[a].Delta_pL) tmp_g = density.finegd.zeros() density.ghat.add(tmp_g, Q_aL) rho_g += tmp_g return rho_g raise RuntimeError('Unknown density type: %s' % density_type)
def calculate_pair_density(self, n1, n2, kpt1, kpt2, ik1, ik2, bzq_index): psit1_G = self.kd.transform_wave_function(kpt1.psit_nG[n1], ik1) psit2_G = self.kd.transform_wave_function(kpt2.psit_nG[n2], ik2) nt_G = psit1_G.conj() * psit2_G s1 = self.kd.sym_k[ik1] s2 = self.kd.sym_k[ik2] t1 = self.kd.time_reversal_k[ik1] t2 = self.kd.time_reversal_k[ik2] k1_c = self.kd.ibzk_kc[kpt1.k] k2_c = self.kd.ibzk_kc[kpt2.k] Q_aL = {} for a in kpt1.P_ani.keys(): b1 = self.kd.symmetry.a_sa[s1, a] b2 = self.kd.symmetry.a_sa[s2, a] S1_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s1]) - self.spos_ac[b1]) S2_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s2]) - self.spos_ac[b2]) assert abs(S1_c.round() - S1_c).max() < 1e-13 assert abs(S2_c.round() - S2_c).max() < 1e-13 x1 = np.exp(2j * pi * np.dot(k1_c, S1_c)) x2 = np.exp(2j * pi * np.dot(k2_c, S2_c)) P1_i = np.dot(self.setups[a].R_sii[s1], kpt1.P_ani[b1][n1]) * x1 P2_i = np.dot(self.setups[a].R_sii[s2], kpt2.P_ani[b2][n2]) * x2 if t1: P1_i = P1_i.conj() if t2: P2_i = P2_i.conj() D_ii = np.outer(P1_i.conj(), P2_i) D_p = pack(D_ii) Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL) self.ghat.add(nt_G, Q_aL, bzq_index) return nt_G
def get(self, nt_G, nt_g, rhot_g): """Get pair densities. nt_G Pair density without compensation charges on the coarse grid nt_g Pair density without compensation charges on the fine grid rhot_g Pair density with compensation charges on the fine grid """ # Coarse grid product np.multiply(self.psit1_G.conj(), self.psit2_G, nt_G) # Interpolate to fine grid self.density.interpolator.apply(nt_G, nt_g) # Determine the compensation charges for each nucleus Q_aL = {} for a, P_ni in self.P_ani.items(): assert P_ni.dtype == float # Generate density matrix P1_i = P_ni[self.n1] P2_i = P_ni[self.n2] D_ii = np.outer(P1_i.conj(), P2_i) # allowed to pack as used in the scalar product with # the symmetric array Delta_pL D_p = pack(D_ii) #FIXME: CHECK THIS D_p = pack(D_ii, tolerance=1e30) # Determine compensation charge coefficients: Q_aL[a] = np.dot(D_p, self.density.setups[a].Delta_pL) # Add compensation charges rhot_g[:] = nt_g[:] self.density.ghat.add(rhot_g, Q_aL)
def calculate_paw_xc_pair_potentials(self, kss_ip): # XC corrections I_asp = {} i = kss_ip.occ_ind p = kss_ip.unocc_ind # s = kss_ip.spin_ind # FIXME, only spin unpolarized works #self.timer.start('Atomic XC') for a, P_ni in self.calc.wfs.kpt_u[kss_ip.kpt_ind].P_ani.items(): I_sp = np.zeros_like(self.calc.density.D_asp[a]) I_sp_2 = np.zeros_like(self.calc.density.D_asp[a]) Pip_ni = self.calc.wfs.kpt_u[kss_ip.spin_ind].P_ani[a] Dip_ii = np.outer(Pip_ni[i], Pip_ni[p]) Dip_p = pack(Dip_ii) # finite difference plus D_sp = self.calc.density.D_asp[a].copy() D_sp[kss_ip.spin_ind] += self.deriv_scale * Dip_p self.xc.calculate_paw_correction(self.calc.wfs.setups[a], D_sp, I_sp) # finite difference minus D_sp_2 = self.calc.density.D_asp[a].copy() D_sp_2[kss_ip.spin_ind] -= self.deriv_scale * Dip_p self.xc.calculate_paw_correction(self.calc.wfs.setups[a], D_sp_2, I_sp_2) # finite difference I_asp[a] = (I_sp - I_sp_2) / (2. * self.deriv_scale) #self.timer.stop('Atomic XC') return I_asp
def calculate_interaction(self, n1_n, n2, kpt1, kpt2, q, k, eik20r_R, eik2r_R, is_ibz2): """Calculate Coulomb interactions. For all n1 in the n1_n list, calculate interaction with n2.""" # number of plane waves: ng1 = self.wfs.ng_k[kpt1.k] ng2 = self.wfs.ng_k[kpt2.k] # Transform to real space and apply symmetry operation: self.timer.start('IFFT1') if is_ibz2: u2_R = self.pd.ifft(kpt2.psit_nG[n2, :ng2], kpt2.k) else: psit2_R = self.pd.ifft(kpt2.psit_nG[n2, :ng2], kpt2.k) * eik20r_R self.timer.start('Symmetry transform') u2_R = self.kd.transform_wave_function(psit2_R, k) / eik2r_R self.timer.stop() self.timer.stop() # Calculate pair densities: nt_nG = self.pd2.zeros(len(n1_n), q=q) for n1, nt_G in zip(n1_n, nt_nG): self.timer.start('IFFT2') u1_R = self.pd.ifft(kpt1.psit_nG[n1, :ng1], kpt1.k) self.timer.stop() nt_R = u1_R.conj() * u2_R self.timer.start('FFT') nt_G[:] = self.pd2.fft(nt_R, q) self.timer.stop() s = self.kd.sym_k[k] time_reversal = self.kd.time_reversal_k[k] k2_c = self.kd.ibzk_kc[kpt2.k] self.timer.start('Compensation charges') Q_anL = {} # coefficients for shape functions for a, P1_ni in kpt1.P_ani.items(): P1_ni = P1_ni[n1_n] if is_ibz2: P2_i = kpt2.P_ani[a][n2] else: b = self.kd.symmetry.a_sa[s, a] S_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s]) - self.spos_ac[b]) assert abs(S_c.round() - S_c).max() < 1e-5 if self.ghat.dtype == complex: x = np.exp(2j * pi * np.dot(k2_c, S_c)) else: x = 1.0 P2_i = np.dot(self.wfs.setups[a].R_sii[s], kpt2.P_ani[b][n2]) * x if time_reversal: P2_i = P2_i.conj() D_np = [] for P1_i in P1_ni: D_ii = np.outer(P1_i.conj(), P2_i) D_np.append(pack(D_ii)) Q_anL[a] = np.dot(D_np, self.wfs.setups[a].Delta_pL) self.timer.start('Expand') if q != self.qlatest: self.f_IG = self.ghat.expand(q) self.qlatest = q self.timer.stop('Expand') # Add compensation charges: self.ghat.add(nt_nG, Q_anL, q, self.f_IG) self.timer.stop('Compensation charges') if self.molecule and n2 in n1_n: nn = (n1_n == n2).nonzero()[0][0] nt_nG[nn] -= self.ngauss_G else: nn = None iG2_G = self.iG2_qG[q] # Calculate energies: e_n = np.empty(len(n1_n)) for n, nt_G in enumerate(nt_nG): e_n[n] = -4 * pi * np.real(self.pd2.integrate(nt_G, nt_G * iG2_G)) self.npairs += 1 if nn is not None: e_n[nn] -= 2 * (self.pd2.integrate(nt_nG[nn], self.vgauss_G) + (self.beta / 2 / pi)**0.5) if self.write_timing_information: t = (time() - self.t0) / len(n1_n) self.log('Time for first pair-density: %10.3f seconds' % t) self.log('Estimated total time: %10.3f seconds' % (t * self.npairs0 / self.world.size)) self.write_timing_information = False return e_n
def with_ae_corrections(self, finegrid=False): """Get pair density including the AE corrections""" nij_g = self.get(finegrid) # Generate the density matrix D_ap = {} # D_aii = {} for a, P_ni in self.P_ani.items(): Pi_i = P_ni[self.i] Pj_i = P_ni[self.j] D_ii = np.outer(Pi_i.conj(), Pj_i) # Note: D_ii is not symmetric but the products of partial waves are # so that we can pack D_ap[a] = pack(D_ii) # D_aii[a] = D_ii # Load partial waves if needed if ((finegrid and (not hasattr(self, 'phi'))) or ((not finegrid) and (not hasattr(self, 'Phi')))): # Splines splines = {} phi_aj = [] phit_aj = [] for a, id in enumerate(self.setups.id_a): if id in splines: phi_j, phit_j = splines[id] else: # Load splines: phi_j, phit_j = self.setups[a].get_partial_waves()[:2] splines[id] = (phi_j, phit_j) phi_aj.append(phi_j) phit_aj.append(phit_j) # Store partial waves as class variables if finegrid: gd = self.density.finegd self.__class__.phi = BasisFunctions(gd, phi_aj) self.__class__.phit = BasisFunctions(gd, phit_aj) self.__class__.phi.set_positions(self.spos_ac) self.__class__.phit.set_positions(self.spos_ac) else: gd = self.density.gd self.__class__.Phi = BasisFunctions(gd, phi_aj) self.__class__.Phit = BasisFunctions(gd, phit_aj) self.__class__.Phi.set_positions(self.spos_ac) self.__class__.Phit.set_positions(self.spos_ac) # Add AE corrections if finegrid: phi = self.phi phit = self.phit gd = self.density.finegd else: phi = self.Phi phit = self.Phit gd = self.density.gd rho_MM = np.zeros((phi.Mmax, phi.Mmax)) M1 = 0 for a, setup in enumerate(self.setups): ni = setup.ni D_p = D_ap.get(a) if D_p is None: D_p = np.empty((ni * (ni + 1) // 2)) if gd.comm.size > 1: gd.comm.broadcast(D_p, self.wfs.rank_a[a]) D_ii = unpack2(D_p) # D_ii = D_aii.get(a) # if D_ii is None: # D_ii = np.empty((ni, ni)) # if gd.comm.size > 1: # gd.comm.broadcast(D_ii, self.wfs.rank_a[a]) M2 = M1 + ni rho_MM[M1:M2, M1:M2] = D_ii M1 = M2 # construct_density assumes symmetric rho_MM and # takes only the upper half of it phi.construct_density(rho_MM, nij_g, q=-1) phit.construct_density(-rho_MM, nij_g, q=-1) # TODO: use ae_valence_density_correction # phi.lfc.ae_valence_density_correction( # rho_MM, nij_g, np.zeros(len(phi.M_W), np.intc), np.zeros(self.na)) # phit.lfc.ae_valence_density_correction( # -rho_MM, nij_g, np.zeros(len(phit.M_W), np.intc), np.zeros(self.na)) return nij_g
import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc.noncollinear import NonCollinearFunctional from gpaw.xc import XC from gpaw.test import equal from gpaw.utilities import pack x = 0.0000001 ra.seed(8) for xc in ['LDA']:#, 'PBE']: print(xc) xc = XC(xc) s = create_setup('N', xc) ni = s.ni D_sp = np.array([pack(np.outer(P_i, P_i)) for P_i in 0.2 * ra.random((2, ni)) - 0.1]) D_sp[1] += D_sp[0] nii = ni * (ni + 1) // 2 E = xc.calculate_paw_correction(s, D_sp) xc = NonCollinearFunctional(xc) Dnc_sp = np.zeros((4, nii)) Dnc_sp[0] = D_sp.sum(0) Dnc_sp[3] = D_sp[0] - D_sp[1] Enc = xc.calculate_paw_correction(s, Dnc_sp) print(E, E-Enc) assert abs(E - Enc) < 1e-11
psit_ig = np.zeros((niAO, n, n, n)) pr.add(psit_ig, coefs) nii = ni * (ni + 1) // 2 D_p = np.zeros(nii) H_p = np.zeros(nii) e_g = np.zeros((n, n, n)) n_g = np.zeros((1, n, n, n)) v_g = np.zeros((1, n, n, n)) P_ni = 0.2 * ra.random((20, ni)) P_ni[:, niAO:] = 0.0 D_ii = np.dot(np.transpose(P_ni), P_ni) D_p = pack(D_ii) p = 0 for i1 in range(niAO): for i2 in range(i1, niAO): n_g += D_p[p] * psit_ig[i1] * psit_ig[i2] p += 1 p += ni - niAO p = create_localized_functions([s.nct], gd, (0.5, 0.5, 0.5)) p.add(n_g[0], np.ones(1)) e_g = gd.zeros() xc.calculate(gd, n_g, v_g, e_g) r2_g = np.sum((np.indices((n, n, n)) - n / 2)**2, axis=0) dv_g = gd.dv * np.less(r2_g, (rcut / a * n)**2)
import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc.noncollinear import NonCollinearFunctional from gpaw.xc import XC from gpaw.test import equal from gpaw.utilities import pack x = 0.0000001 ra.seed(8) for xc in ["LDA"]: # , 'PBE']: print xc xc = XC(xc) s = create_setup("N", xc) ni = s.ni D_sp = np.array([pack(np.outer(P_i, P_i)) for P_i in 0.2 * ra.random((2, ni)) - 0.1]) D_sp[1] += D_sp[0] nii = ni * (ni + 1) // 2 E = xc.calculate_paw_correction(s, D_sp) xc = NonCollinearFunctional(xc) Dnc_sp = np.zeros((4, nii)) Dnc_sp[0] = D_sp.sum(0) Dnc_sp[3] = D_sp[0] - D_sp[1] Enc = xc.calculate_paw_correction(s, Dnc_sp) print E, E - Enc assert abs(E - Enc) < 1e-11
def get_xc(self): """Add xc part of the coupling matrix""" # shorthands paw = self.paw wfs = paw.wfs gd = paw.density.finegd comm = gd.comm eh_comm = self.eh_comm fg = self.finegrid is 2 kss = self.fullkss nij = len(kss) Om_xc = self.Om # initialize densities # nt_sg is the smooth density on the fine grid with spin index if kss.nvspins == 2: # spin polarised ground state calc. nt_sg = paw.density.nt_sg else: # spin unpolarised ground state calc. if kss.npspins == 2: # construct spin polarised densities nt_sg = np.array([.5 * paw.density.nt_sg[0], .5 * paw.density.nt_sg[0]]) else: nt_sg = paw.density.nt_sg # check if D_sp have been changed before D_asp = self.paw.density.D_asp for a, D_sp in D_asp.items(): if len(D_sp) != kss.npspins: if len(D_sp) == 1: D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]]) else: D_asp[a] = np.array([D_sp[0] + D_sp[1]]) # restrict the density if needed if fg: nt_s = nt_sg else: nt_s = self.gd.zeros(nt_sg.shape[0]) for s in range(nt_sg.shape[0]): self.restrict(nt_sg[s], nt_s[s]) gd = paw.density.gd # initialize vxc or fxc if self.derivativeLevel == 0: raise NotImplementedError if kss.npspins == 2: v_g = nt_sg[0].copy() else: v_g = nt_sg.copy() elif self.derivativeLevel == 1: pass elif self.derivativeLevel == 2: fxc_sg = np.zeros(nt_sg.shape) self.xc.calculate_fxc(gd, nt_sg, fxc_sg) else: raise ValueError('derivativeLevel can only be 0,1,2') # self.paw.my_nuclei = [] ns = self.numscale xc = self.xc print('XC', nij, 'transitions', file=self.txt) for ij in range(eh_comm.rank, nij, eh_comm.size): print('XC kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() if self.derivativeLevel >= 1: # vxc is available # We use the numerical two point formula for calculating # the integral over fxc*n_ij. The results are # vvt_s smooth integral # nucleus.I_sp atom based correction matrices (pack2) # stored on each nucleus timer2.start('init v grids') vp_s = np.zeros(nt_s.shape, nt_s.dtype.char) vm_s = np.zeros(nt_s.shape, nt_s.dtype.char) if kss.npspins == 2: # spin polarised nv_s = nt_s.copy() nv_s[kss[ij].pspin] += ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vp_s) nv_s = nt_s.copy() nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vm_s) else: # spin unpolarised nv = nt_s + ns * kss[ij].get(fg) xc.calculate(gd, nv, vp_s) nv = nt_s - ns * kss[ij].get(fg) xc.calculate(gd, nv, vm_s) vvt_s = (0.5 / ns) * (vp_s - vm_s) timer2.stop() # initialize the correction matrices timer2.start('init v corrections') I_asp = {} for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items(): # create the modified density matrix Pi_i = P_ni[kss[ij].i] Pj_i = P_ni[kss[ij].j] P_ii = np.outer(Pi_i, Pj_i) # we need the symmetric form, hence we can pack P_p = pack(P_ii) D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] -= ns * P_p setup = wfs.setups[a] I_sp = np.zeros_like(D_sp) self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp *= -1.0 D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] += ns * P_p self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp /= 2.0 * ns I_asp[a] = I_sp timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) for kq in range(ij, nij): weight = self.weight_Kijkq(ij, kq) if self.derivativeLevel == 0: # only Exc is available if kss.npspins == 2: # spin polarised nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] += kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] -= kss[kq].get(fg) Excpm = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -=\ kss[ij].get(fg) nv_g[kss[kq].pspin] +=\ kss[kq].get(fg) Excmp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -= \ kss[ij].get(fg) nv_g[kss[kq].pspin] -=\ kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) else: # spin unpolarised nv_g = nt_sg + ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excpp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg + ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excpm = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excmp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excmm = xc.get_energy_and_potential(nv_g, v_g) Om_xc[ij, kq] += weight *\ 0.25 * \ (Excpp - Excmp - Excpm + Excmm) / (ns * ns) elif self.derivativeLevel == 1: # vxc is available timer2.start('integrate') Om_xc[ij, kq] += weight *\ self.gd.integrate(kss[kq].get(fg) * vvt_s[kss[kq].pspin]) timer2.stop() timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() elif self.derivativeLevel == 2: # fxc is available if kss.npspins == 2: # spin polarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg[kss[ij].pspin, kss[kq].pspin]) else: # spin unpolarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg) # XXX still numeric derivatives for local terms timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() if ij != kq: Om_xc[kq, ij] = Om_xc[ij, kq] timer.stop() # timer2.write() if ij < (nij - 1): print('XC estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt)
def get_xc(self): """Add xc part of the coupling matrix""" # shorthands paw = self.paw wfs = paw.wfs gd = paw.density.finegd comm = gd.comm eh_comm = self.eh_comm fg = self.finegrid is 2 kss = self.fullkss nij = len(kss) Om_xc = self.Om # initialize densities # nt_sg is the smooth density on the fine grid with spin index if kss.nvspins==2: # spin polarised ground state calc. nt_sg = paw.density.nt_sg else: # spin unpolarised ground state calc. if kss.npspins==2: # construct spin polarised densities nt_sg = np.array([.5*paw.density.nt_sg[0], .5*paw.density.nt_sg[0]]) else: nt_sg = paw.density.nt_sg # check if D_sp have been changed before D_asp = self.paw.density.D_asp for a, D_sp in D_asp.items(): if len(D_sp) != kss.npspins: if len(D_sp) == 1: D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]]) else: D_asp[a] = np.array([D_sp[0] + D_sp[1]]) # restrict the density if needed if fg: nt_s = nt_sg else: nt_s = self.gd.zeros(nt_sg.shape[0]) for s in range(nt_sg.shape[0]): self.restrict(nt_sg[s], nt_s[s]) gd = paw.density.gd # initialize vxc or fxc if self.derivativeLevel==0: raise NotImplementedError if kss.npspins==2: v_g=nt_sg[0].copy() else: v_g=nt_sg.copy() elif self.derivativeLevel==1: pass elif self.derivativeLevel==2: fxc_sg = np.zeros(nt_sg.shape) self.xc.calculate_fxc(gd, nt_sg, fxc_sg) else: raise ValueError('derivativeLevel can only be 0,1,2') ## self.paw.my_nuclei = [] ns=self.numscale xc=self.xc print >> self.txt, 'XC',nij,'transitions' for ij in range(eh_comm.rank, nij, eh_comm.size): print >> self.txt,'XC kss['+'%d'%ij+']' timer = Timer() timer.start('init') timer2 = Timer() if self.derivativeLevel >= 1: # vxc is available # We use the numerical two point formula for calculating # the integral over fxc*n_ij. The results are # vvt_s smooth integral # nucleus.I_sp atom based correction matrices (pack2) # stored on each nucleus timer2.start('init v grids') vp_s=np.zeros(nt_s.shape,nt_s.dtype.char) vm_s=np.zeros(nt_s.shape,nt_s.dtype.char) if kss.npspins == 2: # spin polarised nv_s = nt_s.copy() nv_s[kss[ij].pspin] += ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vp_s) nv_s = nt_s.copy() nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vm_s) else: # spin unpolarised nv = nt_s + ns * kss[ij].get(fg) xc.calculate(gd, nv, vp_s) nv = nt_s - ns * kss[ij].get(fg) xc.calculate(gd, nv, vm_s) vvt_s = (0.5 / ns) * (vp_s - vm_s) timer2.stop() # initialize the correction matrices timer2.start('init v corrections') I_asp = {} for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items(): # create the modified density matrix Pi_i = P_ni[kss[ij].i] Pj_i = P_ni[kss[ij].j] P_ii = np.outer(Pi_i, Pj_i) # we need the symmetric form, hence we can pack P_p = pack(P_ii) D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] -= ns * P_p setup = wfs.setups[a] I_sp = np.zeros_like(D_sp) self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp *= -1.0 D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] += ns * P_p self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp /= 2.0 * ns I_asp[a] = I_sp timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) for kq in range(ij,nij): weight = self.weight_Kijkq(ij, kq) if self.derivativeLevel == 0: # only Exc is available if kss.npspins==2: # spin polarised nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] += kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] -= kss[kq].get(fg) Excpm = xc.get_energy_and_potential(\ nv_g[0],v_g,nv_g[1],v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -=\ kss[ij].get(fg) nv_g[kss[kq].pspin] +=\ kss[kq].get(fg) Excmp = xc.get_energy_and_potential(\ nv_g[0],v_g,nv_g[1],v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -= \ kss[ij].get(fg) nv_g[kss[kq].pspin] -=\ kss[kq].get(fg) Excpp = xc.get_energy_and_potential(\ nv_g[0],v_g,nv_g[1],v_g) else: # spin unpolarised nv_g=nt_sg + ns*kss[ij].get(fg)\ + ns*kss[kq].get(fg) Excpp = xc.get_energy_and_potential(nv_g,v_g) nv_g=nt_sg + ns*kss[ij].get(fg)\ - ns*kss[kq].get(fg) Excpm = xc.get_energy_and_potential(nv_g,v_g) nv_g=nt_sg - ns*kss[ij].get(fg)\ + ns*kss[kq].get(fg) Excmp = xc.get_energy_and_potential(nv_g,v_g) nv_g=nt_sg - ns*kss[ij].get(fg)\ - ns*kss[kq].get(fg) Excmm = xc.get_energy_and_potential(nv_g,v_g) Om_xc[ij,kq] += weight *\ 0.25*(Excpp-Excmp-Excpm+Excmm)/(ns*ns) elif self.derivativeLevel == 1: # vxc is available timer2.start('integrate') Om_xc[ij,kq] += weight*\ self.gd.integrate(kss[kq].get(fg)* vvt_s[kss[kq].pspin]) timer2.stop() timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() elif self.derivativeLevel == 2: # fxc is available if kss.npspins==2: # spin polarised Om_xc[ij,kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg[kss[ij].pspin, kss[kq].pspin]) else: # spin unpolarised Om_xc[ij,kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg) # XXX still numeric derivatives for local terms timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() if ij != kq: Om_xc[kq,ij] = Om_xc[ij,kq] timer.stop() ## timer2.write() if ij < (nij-1): print >> self.txt,'XC estimated time left',\ self.time_left(timer, t0, ij, nij)
def makeU(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl', rotationfile='eps_q__U_pq.pckl', tolerance=1e-5, writeoptimizedpairs=False, dppname='D_pp.pckl', S_w=None): # S_w: None or diagonal of overlap matrix. In the latter case # the optimized and truncated pair orbitals are obtained from # normalized (to 1) orbitals. # # Tolerance is used for truncation of optimized pairorbitals #calc = GPAW(gpwfile, txt=None) from gpaw import GPAW from gpaw.utilities import pack, unpack from gpaw.utilities.blas import rk, gemm from gpaw.mpi import world, MASTER calc = GPAW(gpwfile, txt='pairorb.txt') # XXX gd = calc.wfs.gd setups = calc.wfs.setups myatoms = calc.density.D_asp.keys() del calc # Load orbitals on master and distribute to slaves if world.rank == MASTER: wglobal_wG, P_awi = pickle.load(open(orbitalfile)) Nw = len(wglobal_wG) print('Estimated total (serial) mem usage: %0.3f GB' % ( np.prod(gd.N_c) * Nw**2 * 8 / 1024.**3)) else: wglobal_wG = None Nw = 0 Nw = gd.comm.sum(Nw) #distribute Nw to all nodes w_wG = gd.empty(n=Nw) gd.distribute(wglobal_wG, w_wG) del wglobal_wG # Make pairorbitals f_pG = gd.zeros(n=Nw**2) Np = len(f_pG) for p, (w1, w2) in enumerate(np.ndindex(Nw, Nw)): np.multiply(w_wG[w1], w_wG[w2], f_pG[p]) del w_wG assert f_pG.flags.contiguous # Make pairorbital overlap (lower triangle only) D_pp = np.zeros((Nw**2, Nw**2)) rk(gd.dv, f_pG, 0., D_pp) # Add atomic corrections to pairorbital overlap for a in myatoms: if setups[a].type != 'ghost': P_pp = np.array([pack(np.outer(P_awi[a][w1], P_awi[a][w2])) for w1, w2 in np.ndindex(Nw, Nw)]) I4_pp = setups[a].four_phi_integrals() A = np.zeros((len(I4_pp), len(P_pp))) gemm(1.0, P_pp, I4_pp, 0.0, A, 't') gemm(1.0, A, P_pp, 1.0, D_pp) #D_pp += np.dot(P_pp, np.dot(I4_pp, P_pp.T)) # Summ all contributions to master gd.comm.sum(D_pp, MASTER) if world.rank == MASTER: if S_w is not None: print('renormalizing pairorb overlap matrix (D_pp)') S2 = np.sqrt(S_w) for pa, (wa1, wa2) in enumerate(np.ndindex(Nw, Nw)): for pb, (wb1, wb2) in enumerate(np.ndindex(Nw, Nw)): D_pp[pa, pb] /= S2[wa1] * S2[wa2] * S2[wb1] * S2[wb2] D_pp.dump(dppname) # XXX if the diagonalization below (on MASTER only) # fails, then one can always restart the stuff # below using only the stored D_pp matrix # Determine eigenvalues and vectors on master only eps_q, U_pq = np.linalg.eigh(D_pp, UPLO='L') del D_pp indices = np.argsort(-eps_q.real) eps_q = np.ascontiguousarray(eps_q.real[indices]) U_pq = np.ascontiguousarray(U_pq[:, indices]) # Truncate indices = eps_q > tolerance U_pq = np.ascontiguousarray(U_pq[:, indices]) eps_q = np.ascontiguousarray(eps_q[indices]) # Dump to file pickle.dump((eps_q, U_pq), open(rotationfile, 'wb'), 2) if writeoptimizedpairs is not False: assert world.size == 1 # works in parallel if U and eps are broadcast Uisq_qp = (U_pq / np.sqrt(eps_q)).T.copy() g_qG = gd.zeros(n=len(eps_q)) gemm(1.0, f_pG, Uisq_qp, 0.0, g_qG) g_qG = gd.collect(g_qG) if world.rank == MASTER: P_app = dict([(a, np.array([pack(np.outer(P_wi[w1], P_wi[w2]), tolerance=1e3) for w1, w2 in np.ndindex(Nw, Nw)])) for a, P_wi in P_awi.items()]) P_aqp = dict([(a, np.dot(Uisq_qp, P_pp)) for a, P_pp in P_app.items()]) pickle.dump((g_qG, P_aqp), open(writeoptimizedpairs, 'wb'), 2)
def makeU(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl', rotationfile='eps_q__U_pq.pckl', tolerance=1e-5, writeoptimizedpairs=False, dppname='D_pp.pckl', S_w=None): # S_w: None or diagonal of overlap matrix. In the latter case # the optimized and truncated pair orbitals are obtained from # normalized (to 1) orbitals. # # Tolerance is used for truncation of optimized pairorbitals #calc = GPAW(gpwfile, txt=None) from gpaw import GPAW from gpaw.utilities import pack, unpack from gpaw.utilities.blas import rk, gemm from gpaw.mpi import world, MASTER, serial_comm calc = GPAW(gpwfile, txt='pairorb.txt') # XXX gd = calc.wfs.gd setups = calc.wfs.setups myatoms = calc.density.D_asp.keys() del calc # Load orbitals on master and distribute to slaves if world.rank == MASTER: wglobal_wG, P_awi = pickle.load(open(orbitalfile)) Nw = len(wglobal_wG) print 'Estimated total (serial) mem usage: %0.3f GB' % ( np.prod(gd.N_c) * Nw**2 * 8 / 1024.**3) else: wglobal_wG = None Nw = 0 Nw = gd.comm.sum(Nw) #distribute Nw to all nodes w_wG = gd.empty(n=Nw) gd.distribute(wglobal_wG, w_wG) del wglobal_wG # Make pairorbitals f_pG = gd.zeros(n=Nw**2) Np = len(f_pG) for p, (w1, w2) in enumerate(np.ndindex(Nw, Nw)): np.multiply(w_wG[w1], w_wG[w2], f_pG[p]) del w_wG assert f_pG.flags.contiguous # Make pairorbital overlap (lower triangle only) D_pp = np.zeros((Nw**2, Nw**2)) rk(gd.dv, f_pG, 0., D_pp) # Add atomic corrections to pairorbital overlap for a in myatoms: if setups[a].type != 'ghost': P_pp = np.array([pack(np.outer(P_awi[a][w1], P_awi[a][w2])) for w1, w2 in np.ndindex(Nw, Nw)]) I4_pp = setups[a].four_phi_integrals() A = np.zeros((len(I4_pp), len(P_pp))) gemm(1.0, P_pp, I4_pp, 0.0, A, 't') gemm(1.0, A, P_pp, 1.0, D_pp) #D_pp += np.dot(P_pp, np.dot(I4_pp, P_pp.T)) # Summ all contributions to master gd.comm.sum(D_pp, MASTER) if world.rank == MASTER: if S_w != None: print 'renormalizing pairorb overlap matrix (D_pp)' S2 = np.sqrt(S_w) for pa, (wa1, wa2) in enumerate(np.ndindex(Nw, Nw)): for pb, (wb1, wb2) in enumerate(np.ndindex(Nw, Nw)): D_pp[pa, pb] /= S2[wa1] * S2[wa2] * S2[wb1] * S2[wb2] D_pp.dump(dppname) # XXX if the diagonalization below (on MASTER only) # fails, then one can always restart the stuff # below using only the stored D_pp matrix # Determine eigenvalues and vectors on master only eps_q, U_pq = np.linalg.eigh(D_pp, UPLO='L') del D_pp indices = np.argsort(-eps_q.real) eps_q = np.ascontiguousarray(eps_q.real[indices]) U_pq = np.ascontiguousarray(U_pq[:, indices]) # Truncate indices = eps_q > tolerance U_pq = np.ascontiguousarray(U_pq[:, indices]) eps_q = np.ascontiguousarray(eps_q[indices]) # Dump to file pickle.dump((eps_q, U_pq), open(rotationfile, 'wb'), 2) if writeoptimizedpairs is not False: assert world.size == 1 # works in parallel if U and eps are broadcast Uisq_qp = (U_pq / np.sqrt(eps_q)).T.copy() g_qG = gd.zeros(n=len(eps_q)) gemm(1.0, f_pG, Uisq_qp, 0.0, g_qG) g_qG = gd.collect(g_qG) if world.rank == MASTER: P_app = dict([(a, np.array([pack(np.outer(P_wi[w1], P_wi[w2]), tolerance=1e3) for w1, w2 in np.ndindex(Nw, Nw)])) for a, P_wi in P_awi.items()]) P_aqp = dict([(a, np.dot(Uisq_qp, P_pp)) for a, P_pp in P_app.items()]) pickle.dump((g_qG, P_aqp), open(writeoptimizedpairs, 'wb'), 2)
def get_rpa(self): """calculate RPA part of the omega matrix""" # shorthands kss=self.fullkss finegrid=self.finegrid wfs = self.paw.wfs eh_comm = self.eh_comm # calculate omega matrix nij = len(kss) print >> self.txt,'RPA',nij,'transitions' Om = self.Om for ij in range(eh_comm.rank, nij, eh_comm.size): print >> self.txt,'RPA kss['+'%d'%ij+']=', kss[ij] timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges( finegrid is not 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype.char) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() ## print "shapes 0=",phit.shape,rhot.shape self.restrict(phit_p,phit) else: phit = phit_p rhot = rhot_p for kq in range(ij,nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges( finegrid is 2) timer2.stop() timer2.start('integrate') pre = 2.*sqrt(kss[ij].get_energy()*kss[kq].get_energy()* kss[ij].get_weight()*kss[kq].get_weight()) Om[ij,kq]= pre * self.gd.integrate(rhot*phit) ## print "int=",Om[ij,kq] timer2.stop() # Add atomic corrections timer2.start('integrate corrections 2') Ia = 0. for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items(): Pi_i = P_ni[kss[ij].i] Pj_i = P_ni[kss[ij].j] Dij_ii = np.outer(Pi_i, Pj_i) Dij_p = pack(Dij_ii) Pkq_ni = wfs.kpt_u[kss[kq].spin].P_ani[a] Pk_i = Pkq_ni[kss[kq].i] Pq_i = Pkq_ni[kss[kq].j] Dkq_ii = np.outer(Pk_i, Pq_i) Dkq_p = pack(Dkq_ii) C_pp = wfs.setups[a].M_pp # ---- # 2 > P P C P P # ---- ip jr prst ks qt # prst Ia += 2.0*np.dot(Dkq_p,np.dot(C_pp,Dij_p)) timer2.stop() Om[ij,kq] += pre * self.gd.comm.sum(Ia) if ij == kq: Om[ij,kq] += kss[ij].get_energy()**2 else: Om[kq,ij]=Om[ij,kq] timer.stop() ## timer2.write() if ij < (nij-1): t = timer.get_time(ij) # time for nij-ij calculations t = .5*t*(nij-ij) # estimated time for n*(n+1)/2, n=nij-(ij+1) print >> self.txt,'RPA estimated time left',\ self.timestring(t0*(nij-ij-1)+t)
coefs = np.identity(nao, float) psit_ig = np.zeros((nao, n, n, n)) pr.add(psit_ig, coefs) nii = ni * (ni + 1) // 2 D_p = np.zeros(nii) H_p = np.zeros(nii) e_g = np.zeros((n, n, n)) n_g = np.zeros((1, n, n, n)) v_g = np.zeros((1, n, n, n)) P_ni = 0.2 * ra.random((20, ni)) P_ni[:, nao:] = 0.0 D_ii = np.dot(np.transpose(P_ni), P_ni) D_p = pack(D_ii) p = 0 for i1 in range(nao): for i2 in range(i1, nao): n_g += D_p[p] * psit_ig[i1] * psit_ig[i2] p += 1 p += ni - nao p = create_localized_functions([s.nct], gd, (0.5, 0.5, 0.5)) p.add(n_g[0], np.ones(1)) e_g = gd.zeros() xc.calculate(gd, n_g, v_g, e_g) r2_g = np.sum((np.indices((n, n, n)) - n / 2)**2, axis=0) dv_g = gd.dv * np.less(r2_g, (rcut / a * n)**2)