def para(gobj, mo10, mo_coeff, mo_occ, qed_fac=1): mol = gobj.mol effspin = mol.spin * .5 muB = .5 # Bohr magneton #qed_fac = (nist.G_ELECTRON - 1) orboa = mo_coeff[0][:,mo_occ[0]>0] orbob = mo_coeff[1][:,mo_occ[1]>0] dm0a = numpy.dot(orboa, orboa.T) dm0b = numpy.dot(orbob, orbob.T) dm10a = [reduce(numpy.dot, (mo_coeff[0], x, orboa.T)) for x in mo10[0]] dm10b = [reduce(numpy.dot, (mo_coeff[1], x, orbob.T)) for x in mo10[1]] dm10a = numpy.asarray([x-x.T for x in dm10a]) dm10b = numpy.asarray([x-x.T for x in dm10b]) hso1e = uhf_g.make_h01_soc1e(gobj, mo_coeff, mo_occ, qed_fac) gpara1e =-numpy.einsum('xji,yij->xy', dm10a, hso1e) gpara1e+= numpy.einsum('xji,yij->xy', dm10b, hso1e) gpara1e *= 1./effspin / muB _write(gobj, align(gpara1e)[0], 'SOC(1e)/OZ') if gobj.para_soc2e: gpara2e = gobj.make_para_soc2e((dm0a,dm0b), (dm10a,dm10b), qed_fac) _write(gobj, align(gpara2e)[0], 'SOC(2e)/OZ') else: gpara2e = 0 gpara = gpara1e + gpara2e return gpara
def make_fcdip(hfcobj, dm0, hfc_nuc=None, verbose=None): '''The contribution of Fermi-contact term and dipole-dipole interactions''' log = logger.new_logger(hfcobj, verbose) mol = hfcobj.mol if hfc_nuc is None: hfc_nuc = range(mol.natm) if isinstance(dm0, numpy.ndarray) and dm0.ndim == 2: # RHF DM return numpy.zeros((3,3)) dma, dmb = dm0 spindm = dma - dmb effspin = mol.spin * .5 e_gyro = .5 * nist.G_ELECTRON nuc_mag = .5 * (nist.E_MASS/nist.PROTON_MASS) # e*hbar/2m au2MHz = nist.HARTREE2J / nist.PLANCK * 1e-6 fac = nist.ALPHA**2 / 2 / effspin * e_gyro * au2MHz hfc = [] for i, atm_id in enumerate(hfc_nuc): nuc_gyro = get_nuc_g_factor(mol.atom_symbol(atm_id)) * nuc_mag h1 = _get_integrals_fcdip(mol, atm_id) fcsd = numpy.einsum('xyij,ji->xy', h1, spindm) h1fc = _get_integrals_fc(mol, atm_id) fc = numpy.einsum('ij,ji', h1fc, spindm) sd = fcsd + numpy.eye(3) * fc log.info('FC of atom %d %s (in MHz)', atm_id, fac * nuc_gyro * fc) if hfcobj.verbose >= logger.INFO: _write(hfcobj, align(fac*nuc_gyro*sd)[0], 'SD of atom %d (in MHz)' % atm_id) hfc.append(fac * nuc_gyro * fcsd) return numpy.asarray(hfc)
def kernel(self, mo1=None): cput0 = (time.clock(), time.time()) self.check_sanity() self.dump_flags() mol = self.mol dm0 = self._scf.make_rdm1() hfc_tensor = self.make_fcsd(dm0, self.hfc_nuc) hfc_tensor += self.make_pso_soc(self.hfc_nuc) logger.timer(self, 'HFC tensor', *cput0) if self.verbose > logger.QUIET: for i, atm_id in enumerate(self.hfc_nuc): _write(self, align(hfc_tensor[i])[0], '\nHyperfine coupling tensor of atom %d %s (in MHz)' % (atm_id, mol.atom_symbol(atm_id))) return hfc_tensor
def kernel(self, mo1=None): cput0 = (time.clock(), time.time()) self.check_sanity() self.dump_flags() mol = self.mol dm0 = self._scf.make_rdm1() hfc_tensor = self.make_fcdip(dm0, self.hfc_nuc) hfc_tensor += self.make_pso_soc(self.hfc_nuc) logger.timer(self, 'HFC tensor', *cput0) if self.verbose > logger.QUIET: for i, atm_id in enumerate(self.hfc_nuc): _write(self, align(hfc_tensor[i])[0], '\nHyperfine coupling tensor of atom %d %s (in MHz)' % (atm_id, mol.atom_symbol(atm_id))) return hfc_tensor
def make_pso_soc(hfcobj, hfc_nuc=None): '''Spin-orbit coupling correction''' mol = hfcobj.mol if hfc_nuc is None: hfc_nuc = range(mol.natm) mf = hfcobj._scf mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ effspin = mol.spin * .5 e_gyro = .5 * lib.param.G_ELECTRON nuc_mag = .5 * (lib.param.E_MASS/lib.param.PROTON_MASS) # e*hbar/2m au2MHz = lib.param.HARTREE2J / lib.param.PLANCK * 1e-6 fac = lib.param.ALPHA**4 / 4 / effspin * e_gyro * au2MHz occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 orboa = mo_coeff[0][:, occidxa] orbva = mo_coeff[0][:,~occidxa] orbob = mo_coeff[1][:, occidxb] orbvb = mo_coeff[1][:,~occidxb] # Note sigma_z is considered in h1_soc integral. # mo1b has the associated sign (-) mo1a, mo1b = hfcobj.solve_mo1()[0] dm1a = _dm1_mo2ao(mo1a, orbva, orboa) dm1b = _dm1_mo2ao(mo1b, orbvb, orbob) dm1 = dm1a + dm1b dm1 = dm1 - dm1.transpose(0,2,1) para = [] for n, atm_id in enumerate(hfc_nuc): nuc_gyro = get_nuc_g_factor(mol.atom_symbol(atm_id)) * nuc_mag # Imaginary part of H01 operator # Im[A01 dot p] = Im[vec{r}/r^3 x vec{p}] = Im[-i p (1/r) x p] = -p (1/r) x p mol.set_rinv_origin(mol.atom_coord(atm_id)) h1ao = -mol.intor_asymmetric('int1e_prinvxp', 3) de = numpy.einsum('xij,yij->xy', h1ao, dm1) de *= fac * nuc_gyro if hfcobj.verbose >= logger.INFO: _write(hfcobj, align(de)[0], 'PSO of atom %d (in MHz)' % atm_id) para.append(de) return numpy.asarray(para)
def make_pso_soc(hfcobj, hfc_nuc=None): '''Spin-orbit coupling correction''' mol = hfcobj.mol if hfc_nuc is None: hfc_nuc = range(mol.natm) mf = hfcobj._scf mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ effspin = mol.spin * .5 e_gyro = .5 * nist.G_ELECTRON nuc_mag = .5 * (nist.E_MASS/nist.PROTON_MASS) # e*hbar/2m au2MHz = nist.HARTREE2J / nist.PLANCK * 1e-6 fac = nist.ALPHA**4 / 4 / effspin * e_gyro * au2MHz occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 orboa = mo_coeff[0][:, occidxa] orbva = mo_coeff[0][:,~occidxa] orbob = mo_coeff[1][:, occidxb] orbvb = mo_coeff[1][:,~occidxb] # Note sigma_z is considered in h1_soc integral. # mo1b has the associated sign (-) mo1a, mo1b = hfcobj.solve_mo1()[0] dm1a = _dm1_mo2ao(mo1a, orbva, orboa) dm1b = _dm1_mo2ao(mo1b, orbvb, orbob) dm1 = dm1a + dm1b dm1 = dm1 - dm1.transpose(0,2,1) para = [] for n, atm_id in enumerate(hfc_nuc): nuc_gyro = get_nuc_g_factor(mol.atom_symbol(atm_id)) * nuc_mag # Imaginary part of H01 operator # Im[A01 dot p] = Im[vec{r}/r^3 x vec{p}] = Im[-i p (1/r) x p] = -p (1/r) x p mol.set_rinv_origin(mol.atom_coord(atm_id)) h1ao = -mol.intor_asymmetric('int1e_prinvxp', 3) de = numpy.einsum('xij,yij->xy', h1ao, dm1) de *= fac * nuc_gyro if hfcobj.verbose >= logger.INFO: _write(hfcobj, align(de)[0], 'PSO of atom %d (in MHz)' % atm_id) para.append(de) return numpy.asarray(para)
def make_fcsd(hfcobj, dm0, hfc_nuc=None, verbose=None): log = logger.new_logger(hfcobj, verbose) mol = hfcobj.mol if hfc_nuc is None: hfc_nuc = range(mol.natm) if isinstance(dm0, numpy.ndarray) and dm0.ndim == 2: # RHF DM return numpy.zeros((3,3)) dma, dmb = dm0 spindm = dma - dmb effspin = mol.spin * .5 e_gyro = .5 * lib.param.G_ELECTRON nuc_mag = .5 * (lib.param.E_MASS/lib.param.PROTON_MASS) # e*hbar/2m au2MHz = lib.param.HARTREE2J / lib.param.PLANCK * 1e-6 fac = lib.param.ALPHA**2 / 2 / effspin * e_gyro * au2MHz coords = mol.atom_coords() ao = numint.eval_ao(mol, coords) nao = dma.shape[0] hfc = [] for i, atm_id in enumerate(hfc_nuc): nuc_gyro = get_nuc_g_factor(mol.atom_symbol(atm_id)) * nuc_mag mol.set_rinv_origin(mol.atom_coord(atm_id)) # a01p[mu,sigma] the imaginary part of integral <vec{r}/r^3 cross p> a01p = mol.intor('int1e_sa01sp', 12).reshape(3,4,nao,nao) h1 = -(a01p[:,:3] + a01p[:,:3].transpose(0,1,3,2)) fcsd = numpy.einsum('xyij,ji->xy', h1, spindm) fc = 8*numpy.pi/3 * numpy.einsum('i,j,ji', ao[atm_id], ao[atm_id], spindm) sd = fcsd - numpy.eye(3) * fc log.info('FC of atom %d %s (in MHz)', atm_id, fac * nuc_gyro * fc) if hfcobj.verbose >= logger.INFO: _write(hfcobj, align(fac*nuc_gyro*sd)[0], 'SD of atom %d (in MHz)' % atm_id) hfc.append(fac * nuc_gyro * fcsd) return numpy.asarray(hfc)
def make_para_soc2e(gobj, dm0, dm10, sso_qed_fac=1): if isinstance(gobj.para_soc2e, str): with_sso = 'SSO' in gobj.para_soc2e.upper() with_soo = 'SOO' in gobj.para_soc2e.upper() with_somf = 'SOMF' in gobj.para_soc2e.upper() with_amfi = 'AMFI' in gobj.para_soc2e.upper() assert(not (with_somf and (with_sso or with_soo))) elif gobj.para_soc2e: with_sso = with_soo = True with_somf = with_amfi = False else: with_sso = with_soo = with_somf = False with_amfi = True mol = gobj.mol alpha2 = nist.ALPHA ** 2 effspin = mol.spin * .5 muB = .5 # Bohr magneton #sso_qed_fac = (nist.G_ELECTRON - 1) mf = gobj._scf ni = mf._numint omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, spin=mol.spin) if abs(omega) > 1e-10: raise NotImplementedError mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory*.9-mem_now) v1 = get_vxc_soc(ni, mol, mf.grids, mf.xc, dm0, max_memory=max_memory, verbose=gobj.verbose) dm10a, dm10b = dm10 if with_somf: ej = numpy.einsum('yil,xli->xy', v1[0]+v1[1], dm10a-dm10b) else: ej = numpy.einsum('yil,xli->xy', v1[0], dm10a) ej -= numpy.einsum('yil,xli->xy', v1[1], dm10b) #ej *= -2 #Veff(-2X) approximation of JCP 122 034107 gpara2e = 0 if abs(hyb) > 1e-10: if with_amfi: vj, vk = uhf_g.get_jk_amfi(mol, dm0) else: vj, vk = uhf_g.get_jk(mol, dm0) if with_sso or with_soo: ek = numpy.einsum('yil,xli->xy', vk[0], dm10a) ek -= numpy.einsum('yil,xli->xy', vk[1], dm10b) if with_sso: ej += numpy.einsum('yij,xji->xy', vj[0]+vj[1], dm10a-dm10b) gpara2e -= sso_qed_fac * (ej - hyb * ek) if with_soo: ej += numpy.einsum('yij,xji->xy', vj[0]-vj[1], dm10a+dm10b) gpara2e -= 2 * (ej - hyb * ek) else: # SOMF, see JCP 122, 034107 Eq (19) ej += numpy.einsum('yij,xji->xy', vj[0]+vj[1], dm10a-dm10b) ek = numpy.einsum('yil,xli->xy', vk[0]+vk[1], dm10a-dm10b) gpara2e -= ej - 1.5 * hyb * ek else: if with_amfi: vj = uhf_g.get_j_amfi(mol, dm0) else: vj = uhf_g.get_j(mol, dm0) if with_sso or with_soo: if with_sso: ej += numpy.einsum('yij,xji->xy', vj[0]+vj[1], dm10a-dm10b) gpara2e -= sso_qed_fac * ej if with_soo: ej += numpy.einsum('yij,xji->xy', vj[0]-vj[1], dm10a+dm10b) gpara2e -= 2 * ej else: # SOMF, see JCP 122, 034107 Eq (19) ej += numpy.einsum('yij,xji->xy', vj[0]+vj[1], dm10a-dm10b) gpara2e -= ej gpara2e *= (alpha2/4) / effspin / muB if gobj.verbose >= logger.INFO: _write(gobj, align(gpara2e)[0], 'SOC(2e)/OZ') return gpara2e