def soft_pseudo(self, paw, H_nn, h_nn=None, u=0): if h_nn is None: h_nn = H_nn kpt = paw.wfs.kpt_u[u] pd = self.pair_density deg = 2 / self.nspins fmin = 1e-9 Htpsit_nG = np.zeros(kpt.psit_nG.shape, self.dtype) for n1 in range(self.nbands): psit1_G = kpt.psit_nG[n1] f1 = kpt.f_n[n1] / deg for n2 in range(n1, self.nbands): psit2_G = kpt.psit_nG[n2] f2 = kpt.f_n[n2] / deg if f1 < fmin and f2 < fmin: continue pd.initialize(kpt, n1, n2) pd.get_coarse(self.nt_G) pd.add_compensation_charges(self.nt_G, self.rhot_g) self.poisson_solve(self.vt_g, -self.rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) self.restrict(self.vt_g, self.vt_G) Htpsit_nG[n1] += f2 * self.vt_G * psit2_G if n1 != n2: Htpsit_nG[n2] += f1 * self.vt_G * psit1_G v_aL = paw.density.ghat.dict() paw.density.ghat.integrate(self.vt_g, v_aL) for a, v_L in v_aL.items(): v_ii = unpack(np.dot(paw.wfs.setups[a].Delta_pL, v_L)) P_ni = kpt.P_ani[a] h_nn[:, n1] += f2 * np.dot(P_ni, np.dot(v_ii, P_ni[n2])) if n1 != n2: h_nn[:, n2] += f1 * np.dot(P_ni, np.dot(v_ii, P_ni[n1])) symmetrize(h_nn) # Grrrr why!!! XXX # Fill in lower triangle r2k(0.5 * self.dv, kpt.psit_nG[:], Htpsit_nG, 1.0, H_nn) # Fill in upper triangle from lower tri2full(H_nn, 'L')
def correct_hamiltonian_matrix(self, kpt, H_nn): if not hasattr(kpt, 'vxx_ani'): return if self.gd.comm.rank > 0: H_nn[:] = 0.0 nocc = self.nocc_s[kpt.s] for a, P_ni in kpt.P_ani.items(): H_nn[:nocc, :nocc] += symmetrize(np.inner(P_ni[:nocc], kpt.vxx_ani[a])) self.gd.comm.sum(H_nn) H_nn[:nocc, nocc:] = 0.0 H_nn[nocc:, :nocc] = 0.0
def correct_hamiltonian_matrix(self, kpt, H_nn): if not hasattr(kpt, 'vxx_ani'): return # if self.gd.comm.rank > 0: # H_nn[:] = 0.0 nocc = self.nocc_s[kpt.s] nbands = len(kpt.vt_nG) for a, P_ni in kpt.P_ani.items(): H_nn[:nbands, :nbands] += symmetrize( np.inner(P_ni[:nbands], kpt.vxx_ani[a])) # self.gd.comm.sum(H_nn) if not self.unocc or self.excitation is not None: H_nn[:nocc, nocc:] = 0.0 H_nn[nocc:, :nocc] = 0.0
def apply_orbital_dependent_hamiltonian(self, kpt, psit_nG, Htpsit_nG=None, dH_asp=None): if kpt.f_n is None: return deg = 2 // self.nspins # Spin degeneracy hybrid = self.hybrid P_ani = kpt.P_ani setups = self.setups is_cam = self.is_cam vt_g = self.finegd.empty() if self.gd is not self.finegd: vt_G = self.gd.empty() if self.rsf == 'Yukawa': y_vt_g = self.finegd.empty() # if self.gd is not self.finegd: # y_vt_G = self.gd.empty() nocc = int(ceil(kpt.f_n.sum())) // (3 - self.nspins) if self.excitation is not None: ex_band = nocc - self.excited - 1 if self.excitation == 'singlet': ex_weight = -1 elif self.excitation == 'triplet': ex_weight = +1 else: ex_weight = 0 if self.unocc or self.excitation is not None: nbands = len(kpt.f_n) else: nbands = nocc self.nocc_s[kpt.s] = nocc if Htpsit_nG is not None: kpt.vt_nG = self.gd.empty(nbands) kpt.vxx_ani = {} kpt.vxx_anii = {} for a, P_ni in P_ani.items(): I = P_ni.shape[1] kpt.vxx_ani[a] = np.zeros((nbands, I)) kpt.vxx_anii[a] = np.zeros((nbands, I, I)) exx = 0.0 ekin = 0.0 # XXXX nbands can be different numbers on different cpus! # That means some will execute the loop and others not. # And deadlocks with augment-grids. # Determine pseudo-exchange for n1 in range(nbands): psit1_G = psit_nG[n1] f1 = kpt.f_n[n1] / deg for n2 in range(n1, nbands): psit2_G = psit_nG[n2] f2 = kpt.f_n[n2] / deg if n1 != n2 and f1 == 0 and f1 == f2: continue # Don't work on double unocc. bands # Double count factor: dc = (1 + (n1 != n2)) * deg nt_G, rhot_g = self.calculate_pair_density( n1, n2, psit_nG, P_ani) vt_g[:] = 0.0 # XXXXX This will go wrong because we are solving the # Poisson equation on the distribution of gd, not finegd # Or maybe it's fixed now self.poissonsolver.solve(vt_g, -rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) vt_g *= hybrid if self.rsf == 'Yukawa': y_vt_g[:] = 0.0 self.screened_poissonsolver.solve(y_vt_g, -rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) if is_cam: # Cam like correction y_vt_g *= self.cam_beta else: y_vt_g *= hybrid vt_g -= y_vt_g if self.gd is self.finegd: vt_G = vt_g else: self.restrictor.apply(vt_g, vt_G) # Integrate the potential on fine and coarse grids int_fine = self.finegd.integrate(vt_g * rhot_g) int_coarse = self.gd.integrate(vt_G * nt_G) if self.gd.comm.rank == 0: # only add to energy on master CPU exx += 0.5 * dc * f1 * f2 * int_fine ekin -= dc * f1 * f2 * int_coarse if Htpsit_nG is not None: Htpsit_nG[n1] += f2 * vt_G * psit2_G if n1 == n2: kpt.vt_nG[n1] = f1 * vt_G if self.excitation is not None and n1 == ex_band: Htpsit_nG[nocc:] += f1 * vt_G * psit_nG[nocc:] else: if self.excitation is None or n1 != ex_band \ or n2 < nocc: Htpsit_nG[n2] += f1 * vt_G * psit1_G else: Htpsit_nG[n2] += f1 * ex_weight * vt_G * psit1_G # Update the vxx_uni and vxx_unii vectors of the nuclei, # used to determine the atomic hamiltonian, and the # residuals v_aL = self.ghat.dict() self.ghat.integrate(vt_g, v_aL) for a, v_L in v_aL.items(): v_ii = unpack(np.dot(setups[a].Delta_pL, v_L)) v_ni = kpt.vxx_ani[a] v_nii = kpt.vxx_anii[a] P_ni = P_ani[a] v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2]) if n1 != n2: if self.excitation is None or n1 != ex_band or \ n2 < nocc: v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1]) else: v_ni[n2] += f1 * ex_weight * \ np.dot(v_ii, P_ni[n1]) else: # XXX Check this: v_nii[n1] = f1 * v_ii if self.excitation is not None and n1 == ex_band: for nuoc in range(nocc, nbands): v_ni[nuoc] += f1 * \ np.dot(v_ii, P_ni[nuoc]) def calculate_vv(ni, D_ii, M_pp, weight, addme=False): """Calculate the local corrections depending on Mpp.""" dexx = 0 dekin = 0 if not addme: addsign = -2.0 else: addsign = 2.0 for i1 in range(ni): for i2 in range(ni): A = 0.0 for i3 in range(ni): p13 = packed_index(i1, i3, ni) for i4 in range(ni): p24 = packed_index(i2, i4, ni) A += M_pp[p13, p24] * D_ii[i3, i4] p12 = packed_index(i1, i2, ni) if Htpsit_nG is not None: dH_p[p12] += addsign * weight / \ deg * A / ((i1 != i2) + 1) dekin += 2 * weight / deg * D_ii[i1, i2] * A dexx -= weight / deg * D_ii[i1, i2] * A return (dexx, dekin) # Apply the atomic corrections to the energy and the Hamiltonian # matrix for a, P_ni in P_ani.items(): setup = setups[a] if Htpsit_nG is not None: # Add non-trivial corrections the Hamiltonian matrix h_nn = symmetrize( np.inner(P_ni[:nbands], kpt.vxx_ani[a][:nbands])) ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal()) dH_p = dH_asp[a][kpt.s] # Get atomic density and Hamiltonian matrices D_p = self.density.D_asp[a][kpt.s] D_ii = unpack2(D_p) ni = len(D_ii) # Add atomic corrections to the valence-valence exchange energy # -- # > D C D # -- ii iiii ii (dexx, dekin) = calculate_vv(ni, D_ii, setup.M_pp, hybrid) ekin += dekin exx += dexx if self.rsf is not None: Mg_pp = setup.calculate_yukawa_interaction(self.omega) if is_cam: (dexx, dekin) = calculate_vv(ni, D_ii, Mg_pp, self.cam_beta, addme=True) else: (dexx, dekin) = calculate_vv(ni, D_ii, Mg_pp, hybrid, addme=True) ekin -= dekin exx -= dexx # Add valence-core exchange energy # -- # > X D # -- ii ii if setup.X_p is not None: exx -= hybrid * np.dot(D_p, setup.X_p) if Htpsit_nG is not None: dH_p -= hybrid * setup.X_p ekin += hybrid * np.dot(D_p, setup.X_p) if self.rsf == 'Yukawa' and setup.X_pg is not None: if is_cam: thybrid = self.cam_beta # 0th order else: thybrid = hybrid exx += thybrid * np.dot(D_p, setup.X_pg) if Htpsit_nG is not None: dH_p += thybrid * setup.X_pg ekin -= thybrid * np.dot(D_p, setup.X_pg) elif self.rsf == 'Yukawa' and setup.X_pg is None: thybrid = exp(-3.62e-2 * self.omega) # educated guess if is_cam: thybrid *= self.cam_beta else: thybrid *= hybrid exx += thybrid * np.dot(D_p, setup.X_p) if Htpsit_nG is not None: dH_p += thybrid * setup.X_p ekin -= thybrid * np.dot(D_p, setup.X_p) # Add core-core exchange energy if kpt.s == 0: if self.rsf is None or is_cam: if is_cam: exx += self.cam_alpha * setup.ExxC else: exx += hybrid * setup.ExxC self.exx_s[kpt.s] = self.gd.comm.sum(exx) self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)
def apply_orbital_dependent_hamiltonian(self, kpt, psit_nG, Htpsit_nG=None, dH_asp=None): if kpt.f_n is None: return deg = 2 // self.nspins # Spin degeneracy hybrid = self.hybrid P_ani = kpt.P_ani setups = self.setups vt_g = self.finegd.empty() if self.gd is not self.finegd: vt_G = self.gd.empty() nocc = int(kpt.f_n.sum()) // (3 - self.nspins) if self.unocc: nbands = len(kpt.f_n) else: nbands = nocc self.nocc_s[kpt.s] = nocc if Htpsit_nG is not None: kpt.vt_nG = self.gd.empty(nbands) kpt.vxx_ani = {} kpt.vxx_anii = {} for a, P_ni in P_ani.items(): I = P_ni.shape[1] kpt.vxx_ani[a] = np.zeros((nbands, I)) kpt.vxx_anii[a] = np.zeros((nbands, I, I)) exx = 0.0 ekin = 0.0 # Determine pseudo-exchange for n1 in range(nbands): psit1_G = psit_nG[n1] f1 = kpt.f_n[n1] / deg for n2 in range(n1, nbands): psit2_G = psit_nG[n2] f2 = kpt.f_n[n2] / deg # Double count factor: dc = (1 + (n1 != n2)) * deg nt_G, rhot_g = self.calculate_pair_density(n1, n2, psit_nG, P_ani) vt_g[:] = 0.0 iter = self.poissonsolver.solve(vt_g, -rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) vt_g *= hybrid if self.gd is self.finegd: vt_G = vt_g else: self.restrictor.apply(vt_g, vt_G) # Integrate the potential on fine and coarse grids int_fine = self.finegd.integrate(vt_g * rhot_g) int_coarse = self.gd.integrate(vt_G * nt_G) if self.gd.comm.rank == 0: # only add to energy on master CPU exx += 0.5 * dc * f1 * f2 * int_fine ekin -= dc * f1 * f2 * int_coarse if Htpsit_nG is not None: Htpsit_nG[n1] += f2 * vt_G * psit2_G if n1 == n2: kpt.vt_nG[n1] = f1 * vt_G else: Htpsit_nG[n2] += f1 * vt_G * psit1_G # Update the vxx_uni and vxx_unii vectors of the nuclei, # used to determine the atomic hamiltonian, and the # residuals v_aL = self.ghat.dict() self.ghat.integrate(vt_g, v_aL) for a, v_L in v_aL.items(): v_ii = unpack(np.dot(setups[a].Delta_pL, v_L)) v_ni = kpt.vxx_ani[a] v_nii = kpt.vxx_anii[a] P_ni = P_ani[a] v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2]) if n1 != n2: v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1]) else: # XXX Check this: v_nii[n1] = f1 * v_ii # Apply the atomic corrections to the energy and the Hamiltonian matrix for a, P_ni in P_ani.items(): setup = setups[a] if Htpsit_nG is not None: # Add non-trivial corrections the Hamiltonian matrix h_nn = symmetrize(np.inner(P_ni[:nbands], kpt.vxx_ani[a][:nbands])) ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal()) dH_p = dH_asp[a][kpt.s] # Get atomic density and Hamiltonian matrices D_p = self.density.D_asp[a][kpt.s] D_ii = unpack2(D_p) ni = len(D_ii) # Add atomic corrections to the valence-valence exchange energy # -- # > D C D # -- ii iiii ii for i1 in range(ni): for i2 in range(ni): A = 0.0 for i3 in range(ni): p13 = packed_index(i1, i3, ni) for i4 in range(ni): p24 = packed_index(i2, i4, ni) A += setup.M_pp[p13, p24] * D_ii[i3, i4] p12 = packed_index(i1, i2, ni) if Htpsit_nG is not None: dH_p[p12] -= 2 * hybrid / deg * A / ((i1 != i2) + 1) ekin += 2 * hybrid / deg * D_ii[i1, i2] * A exx -= hybrid / deg * D_ii[i1, i2] * A # Add valence-core exchange energy # -- # > X D # -- ii ii if setup.X_p is not None: exx -= hybrid * np.dot(D_p, setup.X_p) if Htpsit_nG is not None: dH_p -= hybrid * setup.X_p ekin += hybrid * np.dot(D_p, setup.X_p) # Add core-core exchange energy if kpt.s == 0: exx += hybrid * setup.ExxC self.exx_s[kpt.s] = self.gd.comm.sum(exx) self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)
def apply_orbital_dependent_hamiltonian(self, kpt, psit_nG, Htpsit_nG=None, dH_asp=None): if kpt.f_n is None: return deg = 2 // self.nspins # Spin degeneracy hybrid = self.hybrid P_ani = kpt.P_ani setups = self.setups vt_g = self.finegd.empty() if self.gd is not self.finegd: vt_G = self.gd.empty() nocc = int(kpt.f_n.sum()) // (3 - self.nspins) if self.unocc: nbands = len(kpt.f_n) else: nbands = nocc self.nocc_s[kpt.s] = nocc if Htpsit_nG is not None: kpt.vt_nG = self.gd.empty(nbands) kpt.vxx_ani = {} kpt.vxx_anii = {} for a, P_ni in P_ani.items(): I = P_ni.shape[1] kpt.vxx_ani[a] = np.zeros((nbands, I)) kpt.vxx_anii[a] = np.zeros((nbands, I, I)) exx = 0.0 ekin = 0.0 # Determine pseudo-exchange for n1 in range(nbands): psit1_G = psit_nG[n1] f1 = kpt.f_n[n1] / deg for n2 in range(n1, nbands): psit2_G = psit_nG[n2] f2 = kpt.f_n[n2] / deg # Double count factor: dc = (1 + (n1 != n2)) * deg nt_G, rhot_g = self.calculate_pair_density( n1, n2, psit_nG, P_ani) vt_g[:] = 0.0 iter = self.poissonsolver.solve(vt_g, -rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) vt_g *= hybrid if self.gd is self.finegd: vt_G = vt_g else: self.restrictor.apply(vt_g, vt_G) # Integrate the potential on fine and coarse grids int_fine = self.finegd.integrate(vt_g * rhot_g) int_coarse = self.gd.integrate(vt_G * nt_G) if self.gd.comm.rank == 0: # only add to energy on master CPU exx += 0.5 * dc * f1 * f2 * int_fine ekin -= dc * f1 * f2 * int_coarse if Htpsit_nG is not None: Htpsit_nG[n1] += f2 * vt_G * psit2_G if n1 == n2: kpt.vt_nG[n1] = f1 * vt_G else: Htpsit_nG[n2] += f1 * vt_G * psit1_G # Update the vxx_uni and vxx_unii vectors of the nuclei, # used to determine the atomic hamiltonian, and the # residuals v_aL = self.ghat.dict() self.ghat.integrate(vt_g, v_aL) for a, v_L in v_aL.items(): v_ii = unpack(np.dot(setups[a].Delta_pL, v_L)) v_ni = kpt.vxx_ani[a] v_nii = kpt.vxx_anii[a] P_ni = P_ani[a] v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2]) if n1 != n2: v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1]) else: # XXX Check this: v_nii[n1] = f1 * v_ii # Apply the atomic corrections to the energy and the Hamiltonian matrix for a, P_ni in P_ani.items(): setup = setups[a] if Htpsit_nG is not None: # Add non-trivial corrections the Hamiltonian matrix h_nn = symmetrize( np.inner(P_ni[:nbands], kpt.vxx_ani[a][:nbands])) ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal()) dH_p = dH_asp[a][kpt.s] # Get atomic density and Hamiltonian matrices D_p = self.density.D_asp[a][kpt.s] D_ii = unpack2(D_p) ni = len(D_ii) # Add atomic corrections to the valence-valence exchange energy # -- # > D C D # -- ii iiii ii for i1 in range(ni): for i2 in range(ni): A = 0.0 for i3 in range(ni): p13 = packed_index(i1, i3, ni) for i4 in range(ni): p24 = packed_index(i2, i4, ni) A += setup.M_pp[p13, p24] * D_ii[i3, i4] p12 = packed_index(i1, i2, ni) if Htpsit_nG is not None: dH_p[p12] -= 2 * hybrid / deg * A / ((i1 != i2) + 1) ekin += 2 * hybrid / deg * D_ii[i1, i2] * A exx -= hybrid / deg * D_ii[i1, i2] * A # Add valence-core exchange energy # -- # > X D # -- ii ii if setup.X_p is not None: exx -= hybrid * np.dot(D_p, setup.X_p) if Htpsit_nG is not None: dH_p -= hybrid * setup.X_p ekin += hybrid * np.dot(D_p, setup.X_p) # Add core-core exchange energy if kpt.s == 0: exx += hybrid * setup.ExxC self.exx_s[kpt.s] = self.gd.comm.sum(exx) self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)