def coulomb_am(self, sp1, R1, sp2, R2, **kvargs): """ Computes Coulomb overlap for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. <a|r^-1|b> = \iint a(r)|r-r'|b(r') dr dr' Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of Coulomb overlaps The procedure uses the angular momentum algebra and spherical Bessel transform. It is almost a repetition of bilocal overlaps. """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1,sp2)] oo2co = np.zeros(shape) R2mR1 = np.array(R2)-np.array(R1) dist,ylm = np.sqrt(sum(R2mR1*R2mR1)), csphar( R2mR1, 2*self.jmx+1 ) cS = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) cmat = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) rS = np.zeros((self.jmx*2+1,self.jmx*2+1)) f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2*self.jmx+1), dtype = np.float64) _j = self.jmx dkappa = np.log(self.kk[self.nr-1]/self.kk[0])/(self.nr-1) if use_numba: bessel_pp = np.zeros((_j*2+1, self.nr)) for L in range(2*_j+1): bessel_pp[L, :] = scipy.special.spherical_jn(L, dist*self.kk)*self.kk calc_oo2co(bessel_pp, dkappa, np.array(self.ao1.sp2info[sp1]), np.array(self.ao1.sp2info[sp2]), self.ao1.psi_log_mom[sp1], self.ao1.psi_log_mom[sp2], self.njm, self._gaunt_iptr, self._gaunt_data, ylm, _j, self.jmx, self._tr_c2r, self._conj_c2r, l2S, cS, rS, cmat, oo2co) else: bessel_pp = np.zeros((_j*2+1, self.nr)) for L in range(2*_j+1): bessel_pp[L, :] = scipy.special.spherical_jn(L, dist*self.kk)*self.kk for mu2,l2,s2,f2 in self.ao1.sp2info[sp2]: for mu1,l1,s1,f1 in self.ao1.sp2info[sp1]: f1f2_mom = self.ao1.psi_log_mom[sp2][mu2,:] * self.ao1.psi_log_mom[sp1][mu1,:] l2S.fill(0.0) for l3 in range( abs(l1-l2), l1+l2+1): l2S[l3] = (f1f2_mom[:]*bessel_pp[l3,:]).sum() + f1f2_mom[0]*bessel_pp[l3,0]/dkappa cS.fill(0.0) for m1 in range(-l1,l1+1): for m2 in range(-l2,l2+1): gc,m3 = self.get_gaunt(l1,-m1,l2,m2), m2-m1 for l3ind,l3 in enumerate(range(abs(l1-l2),l1+l2+1)): if abs(m3) > l3 : continue cS[m1+_j,m2+_j] = cS[m1+_j,m2+_j] + l2S[l3]*ylm[ l3*(l3+1)+m3] *\ gc[l3ind] * (-1.0)**((3*l1+l2+l3)//2+m2) self.c2r_( l1,l2, self.jmx,cS,rS,cmat) oo2co[s1:f1,s2:f2] = rS[-l1+_j:l1+_j+1,-l2+_j:l2+_j+1] #sys.exit() oo2co = oo2co * (4*np.pi)**2 * self.interp_pp.dg_jt return oo2co
def test_csphar(self): """ """ from pyscf.nao.m_csphar_talman_libnao import csphar_talman_libnao, talman2world rvec = np.array([0.1, 0.2, -0.4]) lmax = 3 ylm_py = csphar(rvec, lmax) ylm_jt = csphar_talman_libnao(rvec, lmax) self.assertEqual(len(ylm_py), (lmax+1)**2) self.assertEqual(len(ylm_jt), (lmax+1)**2) self.assertAlmostEqual(ylm_py[1], 0.075393004386513446-0.15078600877302686j) rvecs = [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0], [0.1, 0.2, -0.4], [5.1, 2.2, -9.4], [0.9, 0.6, -0.2]] for rvec in rvecs: ylm_py_ref = csphar(rvec, lmax) ylm_py = talman2world(csphar_talman_libnao(rvec, lmax)) for y1,y2 in zip(ylm_py_ref, ylm_py): self.assertAlmostEqual(y1,y2)
def test_csphar(self): """ """ from pyscf.nao.m_csphar import csphar from pyscf.nao.m_csphar_talman_libnao import csphar_talman_libnao, talman2world rvec = np.array([0.1, 0.2, -0.4]) lmax = 3 ylm_py = csphar(rvec, lmax) ylm_jt = csphar_talman_libnao(rvec, lmax) self.assertEqual(len(ylm_py), (lmax+1)**2) self.assertEqual(len(ylm_jt), (lmax+1)**2) self.assertAlmostEqual(ylm_py[1], 0.075393004386513446-0.15078600877302686j) rvecs = [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0], [0.1, 0.2, -0.4], [5.1, 2.2, -9.4], [0.9, 0.6, -0.2]] for rvec in rvecs: ylm_py_ref = csphar(rvec, lmax) ylm_py = talman2world(csphar_talman_libnao(rvec, lmax)) for y1,y2 in zip(ylm_py_ref, ylm_py): self.assertAlmostEqual(y1,y2)
def coulomb_am(self, sp1, R1, sp2, R2, **kvargs): r""" Computes Coulomb overlap for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. <a|r^-1|b> = \iint a(r)|r-r'|b(r') dr dr' Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of Coulomb overlaps The procedure uses the angular momentum algebra and spherical Bessel transform. It is almost a repetition of bilocal overlaps. """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1, sp2)] oo2co = np.zeros(shape) R2mR1 = np.array(R2) - np.array(R1) dist, ylm = np.sqrt(sum(R2mR1 * R2mR1)), csphar(R2mR1, 2 * self.jmx + 1) cS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) cmat = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) rS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1)) f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2 * self.jmx + 1), dtype=np.float64) _j = self.jmx dkappa = np.log(self.kk[self.nr - 1] / self.kk[0]) / (self.nr - 1) if use_numba: bessel_pp = np.zeros((_j * 2 + 1, self.nr)) for L in range(2 * _j + 1): bessel_pp[L, :] = scipy.special.spherical_jn( L, dist * self.kk) * self.kk calc_oo2co(bessel_pp, dkappa, np.array(self.ao1.sp2info[sp1]), np.array(self.ao1.sp2info[sp2]), self.ao1.psi_log_mom[sp1], self.ao1.psi_log_mom[sp2], self.njm, self._gaunt_iptr, self._gaunt_data, ylm, _j, self.jmx, self._tr_c2r, self._conj_c2r, l2S, cS, rS, cmat, oo2co) else: bessel_pp = np.zeros((_j * 2 + 1, self.nr)) for L in range(2 * _j + 1): bessel_pp[L, :] = scipy.special.spherical_jn( L, dist * self.kk) * self.kk for mu2, l2, s2, f2 in self.ao1.sp2info[sp2]: for mu1, l1, s1, f1 in self.ao1.sp2info[sp1]: f1f2_mom = self.ao1.psi_log_mom[sp2][ mu2, :] * self.ao1.psi_log_mom[sp1][mu1, :] l2S.fill(0.0) for l3 in range(abs(l1 - l2), l1 + l2 + 1): l2S[l3] = (f1f2_mom[:] * bessel_pp[l3, :]).sum( ) + f1f2_mom[0] * bessel_pp[l3, 0] / dkappa cS.fill(0.0) for m1 in range(-l1, l1 + 1): for m2 in range(-l2, l2 + 1): gc, m3 = self.get_gaunt(l1, -m1, l2, m2), m2 - m1 for l3ind, l3 in enumerate( range(abs(l1 - l2), l1 + l2 + 1)): if abs(m3) > l3: continue cS[m1+_j,m2+_j] = cS[m1+_j,m2+_j] + l2S[l3]*ylm[ l3*(l3+1)+m3] *\ gc[l3ind] * (-1.0)**((3*l1+l2+l3)//2+m2) self.c2r_(l1, l2, self.jmx, cS, rS, cmat) oo2co[s1:f1, s2:f2] = rS[-l1 + _j:l1 + _j + 1, -l2 + _j:l2 + _j + 1] #sys.exit() oo2co = oo2co * (4 * np.pi)**2 * self.interp_pp.dg_jt return oo2co
def overlap_am(self, sp1, R1, sp2, R2): """ Computes overlap for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of orbital overlaps The procedure uses the angular momentum algebra and spherical Bessel transform to compute the bilocal overlaps. """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1, sp2)] overlaps = np.zeros(shape) R2mR1 = np.array(R2) - np.array(R1) psi_log = self.ao1.psi_log psi_log_mom = self.ao1.psi_log_mom sp_mu2rcut = self.ao1.sp_mu2rcut sp2info = self.ao1.sp2info ylm = csphar(R2mR1, 2 * self.jmx + 1) dist = np.sqrt(sum(R2mR1 * R2mR1)) cS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) cmat = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) rS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1)) if (dist < 1.0e-5): for [mu1, l1, s1, f1], ff1 in zip(sp2info[sp1], psi_log[sp1]): for [mu2, l2, s2, f2], ff2 in zip(sp2info[sp2], psi_log[sp2]): cS.fill(0.0) rS.fill(0.0) if l1 == l2: sum1 = sum(ff1 * ff2 * self.rr3_dr) for m1 in range(-l1, l1 + 1): cS[m1 + self.jmx, m1 + self.jmx] = sum1 self.c2r_(l1, l2, self.jmx, cS, rS, cmat) overlaps[s1:f1, s2:f2] = rS[-l1 + self.jmx:l1 + 1 + self.jmx, -l2 + self.jmx:l2 + 1 + self.jmx] else: f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2 * self.jmx + 1)) ir, coeffs = comp_coeffs(self.interp_rr, dist) _j = self.jmx for [mu2, l2, s2, f2], rcut2, ff2 in zip(sp2info[sp2], sp_mu2rcut[sp2], psi_log_mom[sp2]): for [mu1, l1, s1, f1], rcut1, ff1 in zip(sp2info[sp1], sp_mu2rcut[sp1], psi_log_mom[sp1]): if rcut1 + rcut2 < dist: continue f1f2_mom = ff2 * ff1 l2S.fill(0.0) for l3 in range(abs(l1 - l2), l1 + l2 + 1): f1f2_rea = self.sbt(f1f2_mom, l3, -1) l2S[l3] = (f1f2_rea[ir:ir + 6] * coeffs).sum() * self.const * 4 * np.pi cS.fill(0.0) for m1 in range(-l1, l1 + 1): for m2 in range(-l2, l2 + 1): gc, m3 = self.get_gaunt(l1, -m1, l2, m2), m2 - m1 for l3ind, l3 in enumerate( range(abs(l1 - l2), l1 + l2 + 1)): if abs(m3) > l3: continue cS[m1 + _j, m2 + _j] = cS[m1 + _j, m2 + _j] + l2S[l3] * ylm[ l3 * (l3 + 1) + m3] * gc[l3ind] * (-1.0)**( (3 * l1 + l2 + l3) // 2 + m2) self.c2r_(l1, l2, self.jmx, cS, rS, cmat) overlaps[s1:f1, s2:f2] = rS[-l1 + _j:l1 + _j + 1, -l2 + _j:l2 + _j + 1] return overlaps
def comp_vext_tem_pyth(self, ao_log=None, numba_parallel=True): """ Compute the external potential created by a moving charge Python version """ def c2r_lm(conv, clm, clmm, m): """ clm: sph harmonic l and m clmm: sph harmonic l and -m convert from real to complex spherical harmonic for an unique value of l and m """ rlm = 0.0 if m == 0: rlm = conv._c2r[conv._j, conv._j] * clm else: rlm = conv._c2r[m+conv._j, m+conv._j]*clm +\ conv._c2r[m+conv._j, -m+conv._j]*clmm if rlm.imag > 1e-10: print(rlm) raise ValueError("Non nul imaginary paert for c2r conversion") return rlm.real def get_index_lm(l, m): """ return the index of an array ordered as [l=0 m=0, l=1 m=-1, l=1 m=0, l=1 m=1, ....] """ return (l + 1)**2 - 1 - l + m warnings.warn("Obselete routine use comp_vext_tem") if use_numba: get_time_potential = nb.jit( nopython=True, parallel=numba_parallel)(get_tem_potential_numba) V_time = np.zeros((self.time.size), dtype=np.complex64) aome = ao_matelem_c(self.ao_log.rr, self.ao_log.pp) me = ao_matelem_c( self.ao_log) if ao_log is None else aome.init_one_set(ao_log) atom2s = np.zeros((self.natm + 1), dtype=np.int64) for atom, sp in enumerate(self.atom2sp): atom2s[atom + 1] = atom2s[atom] + me.ao1.sp2norbs[sp] R0 = self.vnorm * self.time[0] * self.vdir + self.beam_offset rr = self.ao_log.rr dr = (np.log(rr[-1]) - np.log(rr[0])) / (rr.size - 1) dt = self.time[1] - self.time[0] dw = self.freq_symm[1] - self.freq_symm[0] wmin = self.freq_symm[0] tmin = self.time[0] nff = self.freq.size ub = self.freq_symm.size // 2 - 1 l2m = [] # list storing m value to corresponding l fact_fft = np.exp(-1.0j * self.freq_symm[ub:ub + nff] * tmin) pre_fact = dt * np.exp(-1.0j * wmin * (self.time - tmin)) for l in range(me.jmx + 1): lm = [] for m in range(-l, l + 1): lm.append(m) l2m.append(np.array(lm)) for atm, sp in enumerate(self.atom2sp): rcut = self.ao_log.sp2rcut[sp] center = self.atom2coord[atm, :] rmax = find_nearrest_index(rr, rcut) si = atom2s[atm] fi = atom2s[atm + 1] for mu, l in enumerate(self.pb.prod_log.sp_mu2j[sp]): s = self.pb.prod_log.sp_mu2s[sp][mu] f = self.pb.prod_log.sp_mu2s[sp][mu + 1] fr_val = self.pb.prod_log.psi_log[sp][mu, :] inte1 = np.sum(fr_val[0:rmax + 1] * rr[0:rmax + 1]**(l + 2) * rr[0:rmax + 1] * dr) for k in range(s, f): V_time.fill(0.0) m = l2m[l][k - s] ind_lm = get_index_lm(l, m) ind_lmm = get_index_lm(l, -m) if use_numba: get_time_potential(self.time, R0, self.vnorm, self.vdir, center, rcut, inte1, rr, dr, fr_val, me._c2r, l, m, me._j, ind_lm, ind_lmm, V_time) else: for it, t in enumerate(self.time): R_sub = R0 + self.vnorm * self.vdir * ( t - self.time[0]) - center norm = np.sqrt(np.dot(R_sub, R_sub)) if norm > rcut: I1 = inte1 / (norm**(l + 1)) I2 = 0.0 else: rsub_max = find_nearrest_index(rr, norm) I1 = np.sum(fr_val[0:rsub_max + 1] * rr[0:rsub_max + 1]**(l + 2) * rr[0:rsub_max + 1]) I2 = np.sum(fr_val[rsub_max + 1:] * rr[rsub_max + 1:] / (rr[rsub_max + 1:]**(l - 1))) I1 = I1 * dr / (norm**(l + 1)) I2 = I2 * (norm**l) * dr clm_tem = csphar(R_sub, l) clm = (4 * np.pi / (2 * l + 1)) * clm_tem[ind_lm] * (I1 + I2) clmm = (4 * np.pi / (2 * l + 1)) * clm_tem[ind_lmm] * (I1 + I2) rlm = c2r_lm(me, clm, clmm, m) V_time[it] = rlm + 0.0j V_time *= pre_fact FT = fft(V_time) self.V_freq[:, si + k] = FT[ub:ub + nff] * fact_fft
def laplace_am(self, sp1, R1, sp2, R2): """ Computes brakets of Laplace operator for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of Laplace operator brakets """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1, sp2)] overlaps = np.zeros(shape) R2mR1 = np.array(R2) - np.array(R1) psi_log = self.ao1.psi_log psi_log_mom = self.ao1.psi_log_mom sp_mu2rcut = self.ao1.sp_mu2rcut sp2info = self.ao1.sp2info pp = self.ao1.pp rr = self.ao1.rr ylm = csphar(R2mR1, 2 * self.jmx + 1) dist = np.sqrt(sum(R2mR1 * R2mR1)) cS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) cmat = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) rS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1)) j = self.jmx if (dist < 1.0e-5): for [mu1, l1, s1, f1], ff1 in zip(sp2info[sp1], psi_log[sp1]): ff1_diff = self.interp_rr.diff(ff1) for [mu2, l2, s2, f2], ff2 in zip(sp2info[sp2], psi_log[sp2]): ff2_diff = self.interp_rr.diff(ff2) cS.fill(0.0) rS.fill(0.0) if l1 == l2: sum2 = sum(ff1_diff * ff2_diff * self.rr3_dr) + l1 * ( l1 + 1) * sum(ff1 * ff2 * rr) * self.dr_jt for m1 in range(-l1, l1 + 1): cS[m1 + self.jmx, m1 + self.jmx] = sum2 self.c2r_(l1, l2, self.jmx, cS, rS, cmat) overlaps[s1:f1, s2:f2] = rS[-l1 + j:l1 + 1 + j, -l2 + j:l2 + 1 + j] else: f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2 * self.jmx + 1)) ir, coeffs = comp_coeffs(self.interp_rr, dist) for [mu2, l2, s2, f2], rcut2, ff2 in zip(sp2info[sp2], sp_mu2rcut[sp2], psi_log_mom[sp2]): for [mu1, l1, s1, f1], rcut1, ff1 in zip(sp2info[sp1], sp_mu2rcut[sp1], psi_log_mom[sp1]): if rcut1 + rcut2 < dist: continue f1f2_mom = ff2 * ff1 * self.pp2 l2S.fill(0.0) for l3 in range(abs(l1 - l2), l1 + l2 + 1): f1f2_rea = self.sbt(f1f2_mom, l3, -1) l2S[l3] = (f1f2_rea[ir:ir + 6] * coeffs).sum() l2S = l2S * self.const * 4 * np.pi cS.fill(0.0) for m1 in range(-l1, l1 + 1): for m2 in range(-l2, l2 + 1): gc, m3 = self.get_gaunt(l1, -m1, l2, m2), m2 - m1 for l3ind, l3 in enumerate( range(abs(l1 - l2), l1 + l2 + 1)): if abs(m3) > l3: continue cS[m1 + j, m2 + j] = cS[m1 + j, m2 + j] + l2S[l3] * ylm[ l3 * (l3 + 1) + m3] * gc[l3ind] * (-1.0)**( (3 * l1 + l2 + l3) // 2 + m2) self.c2r_(l1, l2, self.jmx, cS, rS, cmat) overlaps[s1:f1, s2:f2] = rS[-l1 + j:l1 + j + 1, -l2 + j:l2 + j + 1] return -overlaps
def laplace_am(self, sp1, R1, sp2, R2): """ Computes brakets of Laplace operator for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of Laplace operator brakets """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1,sp2)] overlaps = np.zeros(shape) R2mR1 = np.array(R2)-np.array(R1) psi_log = self.ao1.psi_log psi_log_mom = self.ao1.psi_log_mom sp_mu2rcut = self.ao1.sp_mu2rcut sp2info = self.ao1.sp2info pp = self.ao1.pp rr = self.ao1.rr ylm = csphar( R2mR1, 2*self.jmx+1 ) dist = np.sqrt(sum(R2mR1*R2mR1)) cS = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) cmat = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) rS = np.zeros((self.jmx*2+1,self.jmx*2+1)) j = self.jmx if(dist<1.0e-5): for [mu1,l1,s1,f1],ff1 in zip(sp2info[sp1],psi_log[sp1]): ff1_diff = self.interp_rr.diff(ff1) for [mu2,l2,s2,f2],ff2 in zip(sp2info[sp2],psi_log[sp2]): ff2_diff = self.interp_rr.diff(ff2) cS.fill(0.0); rS.fill(0.0); if l1==l2 : sum2 = sum(ff1_diff*ff2_diff*self.rr3_dr)+l1*(l1+1)*sum(ff1*ff2*rr)*self.dr_jt for m1 in range(-l1,l1+1): cS[m1+self.jmx,m1+self.jmx]=sum2 self.c2r_( l1,l2, self.jmx,cS,rS,cmat) overlaps[s1:f1,s2:f2] = rS[-l1+j:l1+1+j,-l2+j:l2+1+j] else: f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2*self.jmx+1)) ir,coeffs = comp_coeffs(self.interp_rr, dist) for [mu2,l2,s2,f2],rcut2,ff2 in zip(sp2info[sp2],sp_mu2rcut[sp2],psi_log_mom[sp2]): for [mu1,l1,s1,f1],rcut1,ff1 in zip(sp2info[sp1],sp_mu2rcut[sp1],psi_log_mom[sp1]): if rcut1+rcut2<dist: continue f1f2_mom = ff2 * ff1 * self.pp2 l2S.fill(0.0) for l3 in range( abs(l1-l2), l1+l2+1): f1f2_rea = self.sbt(f1f2_mom, l3, -1) l2S[l3] = (f1f2_rea[ir:ir+6]*coeffs).sum() l2S = l2S*self.const*4*np.pi cS.fill(0.0) for m1 in range(-l1,l1+1): for m2 in range(-l2,l2+1): gc, m3 = self.get_gaunt(l1,-m1,l2,m2), m2-m1 for l3ind,l3 in enumerate(range(abs(l1-l2),l1+l2+1)): if abs(m3) > l3 : continue cS[m1+j,m2+j] = cS[m1+j,m2+j] + l2S[l3]*ylm[ l3*(l3+1)+m3] * gc[l3ind] * (-1.0)**((3*l1+l2+l3)//2+m2) self.c2r_( l1,l2, self.jmx,cS,rS,cmat) overlaps[s1:f1,s2:f2] = rS[-l1+j:l1+j+1,-l2+j:l2+j+1] return overlaps
def overlap_am(self, sp1, R1, sp2, R2): """ Computes overlap for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of orbital overlaps The procedure uses the angular momentum algebra and spherical Bessel transform to compute the bilocal overlaps. """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1,sp2)] overlaps = np.zeros(shape) R2mR1 = np.array(R2)-np.array(R1) psi_log = self.ao1.psi_log psi_log_mom = self.ao1.psi_log_mom sp_mu2rcut = self.ao1.sp_mu2rcut sp2info = self.ao1.sp2info ylm = csphar( R2mR1, 2*self.jmx+1 ) dist = np.sqrt(sum(R2mR1*R2mR1)) cS = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) cmat = np.zeros((self.jmx*2+1,self.jmx*2+1), dtype=np.complex128) rS = np.zeros((self.jmx*2+1,self.jmx*2+1)) if(dist<1.0e-5): for [mu1,l1,s1,f1],ff1 in zip(sp2info[sp1],psi_log[sp1]): for [mu2,l2,s2,f2],ff2 in zip(sp2info[sp2],psi_log[sp2]): cS.fill(0.0); rS.fill(0.0); if l1==l2 : sum1 = sum(ff1 * ff2 *self.rr3_dr) for m1 in range(-l1,l1+1): cS[m1+self.jmx,m1+self.jmx]=sum1 self.c2r_( l1,l2, self.jmx,cS,rS,cmat) overlaps[s1:f1,s2:f2] = rS[-l1+self.jmx:l1+1+self.jmx,-l2+self.jmx:l2+1+self.jmx] else: f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2*self.jmx+1)) ir,coeffs = comp_coeffs(self.interp_rr, dist) _j = self.jmx for [mu2,l2,s2,f2],rcut2,ff2 in zip(sp2info[sp2],sp_mu2rcut[sp2],psi_log_mom[sp2]): for [mu1,l1,s1,f1],rcut1,ff1 in zip(sp2info[sp1],sp_mu2rcut[sp1],psi_log_mom[sp1]): if rcut1+rcut2<dist: continue f1f2_mom = ff2 * ff1 l2S.fill(0.0) for l3 in range( abs(l1-l2), l1+l2+1): f1f2_rea = self.sbt(f1f2_mom, l3, -1) l2S[l3] = (f1f2_rea[ir:ir+6]*coeffs).sum()*self.const*4*np.pi cS.fill(0.0) for m1 in range(-l1,l1+1): for m2 in range(-l2,l2+1): gc, m3 = self.get_gaunt(l1,-m1,l2,m2), m2-m1 for l3ind,l3 in enumerate(range(abs(l1-l2),l1+l2+1)): if abs(m3) > l3 : continue cS[m1+_j,m2+_j] = cS[m1+_j,m2+_j] + l2S[l3]*ylm[ l3*(l3+1)+m3] * gc[l3ind] * (-1.0)**((3*l1+l2+l3)//2+m2) self.c2r_( l1,l2, self.jmx,cS,rS,cmat) overlaps[s1:f1,s2:f2] = rS[-l1+_j:l1+_j+1,-l2+_j:l2+_j+1] return overlaps
def coulomb_am(self, sp1, R1, sp2, R2, **kvargs): """ Computes Coulomb overlap for an atom pair. The atom pair is given by a pair of species indices and the coordinates of the atoms. <a|r^-1|b> = \iint a(r)|r-r'|b(r') dr dr' Args: self: class instance of ao_matelem_c sp1,sp2 : specie indices, and R1,R2 : respective coordinates Result: matrix of Coulomb overlaps The procedure uses the angular momentum algebra and spherical Bessel transform. It is almost a repetition of bilocal overlaps. """ shape = [self.ao1.sp2norbs[sp] for sp in (sp1, sp2)] oo2co = np.zeros(shape) R2mR1 = np.array(R2) - np.array(R1) dist, ylm = np.sqrt(sum(R2mR1 * R2mR1)), csphar(R2mR1, 2 * self.jmx + 1) cS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) cmat = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1), dtype=np.complex128) rS = np.zeros((self.jmx * 2 + 1, self.jmx * 2 + 1)) f1f2_mom = np.zeros((self.nr)) l2S = np.zeros((2 * self.jmx + 1), dtype=np.float64) _j = self.jmx # use_numba = False # import h5py # import matplotlib.pyplot as plt # fig = plt.figure(1, figsize=(15, 10)) # log_mom_fortran = h5py.File("pb_coul_aux.hdf5", "r")["sp_local2functs_mom"] # psi_range = np.arange(self.ao1.psi_log_mom[0].shape[1]) # for sp in range(len(self.ao1.psi_log_mom)): # for mu in range(self.ao1.psi_log_mom[sp].shape[0]): # ax = fig.add_subplot(2, 3, mu+1) # error = np.zeros(self.ao1.psi_log_mom[sp].shape[0]) # pyt = self.ao1.psi_log_mom[sp][mu, :] # fort = log_mom_fortran["specie_{0}/ir_mu2v".format(sp+1)].value[mu, :] # ax.plot(psi_range, pyt, "b", linewidth=3, label="python") # ax_twin = ax.twinx() # ax_twin.plot(psi_range, fort, "--g", linewidth=3, label="fortran mu") # for mu2 in range(self.ao1.psi_log_mom[sp].shape[0]): # fort = log_mom_fortran["specie_{0}/ir_mu2v".format(sp+1)].value[mu2, :] # error[mu2] = np.sum(abs(fort-pyt)) # mu_fort = np.argmin(error) # fort = log_mom_fortran["specie_{0}/ir_mu2v".format(sp+1)].value[mu_fort, :] # ax.plot(psi_range, fort, "--r", linewidth=3, label="fortran mumod") # ax.legend() # ax.set_title("mu_python = {0}, mu_fort = {1}".format(mu+1, mu_fort+1), fontsize=20) # #print("look fort: ", np.sum(abs(fort-pyt))) # # fig.tight_layout() # fig.savefig("psi_log_diff.pdf", format="pdf") # #plt.show() # #print("shape: ", self.ao1.psi_log_mom[0].shape) # #sys.exit() #self.ao1.psi_log_mom[sp] = log_mom_fortran["specie_{0}/ir_mu2v".format(sp+1)].value # use_numba=False if use_numba: bessel_pp = np.zeros((_j * 2 + 1, self.nr)) for L in range(2 * _j + 1): bessel_pp[L, :] = scipy.special.spherical_jn( L, dist * self.kk) * self.kk calc_oo2co(bessel_pp, self.interp_pp.dg_jt, np.array(self.ao1.sp2info[sp1]), np.array(self.ao1.sp2info[sp2]), self.ao1.psi_log_mom[sp1], self.ao1.psi_log_mom[sp2], self.njm, self._gaunt_iptr, self._gaunt_data, ylm, _j, self.jmx, self._tr_c2r, self._conj_c2r, l2S, cS, rS, cmat, oo2co) else: bessel_pp = np.zeros((_j * 2 + 1, self.nr)) for L in range(2 * _j + 1): bessel_pp[L, :] = scipy.special.spherical_jn( L, dist * self.kk) * self.kk #print("##############################################") for mu2, l2, s2, f2 in self.ao1.sp2info[sp2]: for mu1, l1, s1, f1 in self.ao1.sp2info[sp1]: f1f2_mom = self.ao1.psi_log_mom[sp2][ mu2, :] * self.ao1.psi_log_mom[sp1][mu1, :] #print("mu1 = {0}, mu2 = {1}: sum(f1f2_mom) = ".format(mu1, mu2), np.sum(abs(f1f2_mom))) l2S.fill(0.0) for l3 in range(abs(l1 - l2), l1 + l2 + 1): l2S[l3] = (f1f2_mom[:] * bessel_pp[l3, :] ).sum() + f1f2_mom[0] * bessel_pp[ l3, 0] / self.interp_pp.dg_jt * 0.995 #print("sum(S) = ", np.sum(abs(l2S))) cS.fill(0.0) for m1 in range(-l1, l1 + 1): for m2 in range(-l2, l2 + 1): gc, m3 = self.get_gaunt(l1, -m1, l2, m2), m2 - m1 for l3ind, l3 in enumerate( range(abs(l1 - l2), l1 + l2 + 1)): if abs(m3) > l3: continue cS[m1+_j,m2+_j] = cS[m1+_j,m2+_j] + l2S[l3]*ylm[ l3*(l3+1)+m3] *\ gc[l3ind] * (-1.0)**((3*l1+l2+l3)//2+m2) self.c2r_(l1, l2, self.jmx, cS, rS, cmat) oo2co[s1:f1, s2:f2] = rS[-l1 + _j:l1 + _j + 1, -l2 + _j:l2 + _j + 1] #sys.exit() oo2co = oo2co * (4 * np.pi)**2 * self.interp_pp.dg_jt return oo2co