def kernel(self, mo1=None): cput0 = (time.clock(), time.time()) self.check_sanity() self.dump_flags() mol = self.mol dm0 = self._scf.make_rdm1() mo_coeff = self._scf.mo_coeff mo_occ = self._scf.mo_occ ssc_dia = self.make_dso(mol, dm0) if mo1 is None: mo1 = self.mo10 = self.solve_mo1()[0] ssc_pso = self.make_pso(mol, mo1, mo_coeff, mo_occ) e11 = ssc_dia + ssc_pso if self.with_fcsd: ssc_fcsd = self.make_fcsd(self.nuc_pair) e11 += ssc_fcsd elif self.with_fc: ssc_fc = self.make_fc(self.nuc_pair) e11 += ssc_fc logger.timer(self, 'spin-spin coupling', *cput0) if self.verbose > logger.QUIET: nuc_mag = .5 * (lib.param.E_MASS / lib.param.PROTON_MASS ) # e*hbar/2m au2Hz = lib.param.HARTREE2J / lib.param.PLANCK #logger.debug('Unit AU -> Hz %s', au2Hz*nuc_mag**2) iso_ssc = au2Hz * nuc_mag**2 * numpy.einsum('kii->k', e11) / 3 natm = mol.natm ktensor = numpy.zeros((natm, natm)) for k, (i, j) in enumerate(self.nuc_pair): ktensor[i, j] = ktensor[j, i] = iso_ssc[k] if self.verbose >= logger.DEBUG: _write(self.stdout, ssc_dia[k]+ssc_para[k], '\nSSC E11 between %d %s and %d %s' \ % (i, self.mol.atom_symbol(i), j, self.mol.atom_symbol(j))) # _write(self.stdout, ssc_dia [k], 'dia-magnetism') # _write(self.stdout, ssc_para[k], 'para-magnetism') gyro = [ get_nuc_g_factor(mol.atom_symbol(ia)) for ia in range(natm) ] jtensor = numpy.einsum('ij,i,j->ij', ktensor, gyro, gyro) label = [ '%2d %-2s' % (ia, mol.atom_symbol(ia)) for ia in range(natm) ] logger.note(self, 'Reduced spin-spin coupling constant K (Hz)') tools.dump_mat.dump_tri(self.stdout, ktensor, label) logger.info(self, '\nNuclear g factor %s', gyro) logger.note(self, 'Spin-spin coupling constant J (Hz)') tools.dump_mat.dump_tri(self.stdout, jtensor, label) return e11
def kernel(hfcobj, with_gaunt=False, verbose=None): log = lib.logger.new_logger(hfcobj, verbose) mf = hfcobj._scf mol = mf.mol # Add finite field to remove degeneracy nuc_spin = numpy.ones(3) * 1e-6 sc = numpy.dot(mf.get_ovlp(), mf.mo_coeff) h0 = reduce(numpy.dot, (sc * mf.mo_energy, sc.conj().T)) c = lib.param.LIGHT_SPEED n4c = h0.shape[0] n2c = n4c // 2 Sigma = numpy.zeros((3, n4c, n4c), dtype=h0.dtype) Sigma[:, :n2c, :n2c] = mol.intor('int1e_sigma_spinor', comp=3) Sigma[:, n2c:, n2c:] = .25 / c**2 * mol.intor('int1e_spsigmasp_spinor', comp=3) hfc = [] for atm_id in range(mol.natm): symb = mol.atom_symbol(atm_id) nuc_mag = .5 * (lib.param.E_MASS / lib.param.PROTON_MASS) # e*hbar/2m nuc_gyro = get_nuc_g_factor(symb) * nuc_mag e_gyro = .5 * lib.param.G_ELECTRON au2MHz = lib.param.HARTREE2J / lib.param.PLANCK * 1e-6 fac = lib.param.ALPHA**2 * nuc_gyro * e_gyro * au2MHz #logger.debug('factor (MHz) %s', fac) h01 = make_h01(mol, 0) mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff if 0: h01b = h0 + numpy.einsum('xij,x->ij', h01, nuc_spin) h01b = reduce(numpy.dot, (mf.mo_coeff.conj().T, h01b, mf.mo_coeff)) mo_energy, v = numpy.linalg.eigh(h01b) mo_coeff = numpy.dot(mf.mo_coeff, v) mo_occ = mf.get_occ(mo_energy, mo_coeff) occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] dm0 = numpy.dot(orbo, orbo.T.conj()) e01 = numpy.einsum('xij,ji->x', h01, dm0) * fac effspin = numpy.einsum('xij,ji->x', Sigma, dm0) * .5 log.debug('atom %d Eff-spin %s', atm_id, effspin.real) e01 = (e01 / effspin).real hfc.append(e01) return numpy.asarray(hfc)
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 * 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] nocca = orboa.shape[1] nvira = orbva.shape[1] noccb = orbob.shape[1] nvirb = orbvb.shape[1] mo1a, mo1b = solve_mo1_pso(hfcobj, hfc_nuc) mo1a = mo1a.reshape(len(hfc_nuc), 3, nvira, nocca) mo1b = mo1b.reshape(len(hfc_nuc), 3, nvirb, noccb) dm0 = hfcobj._scf.make_rdm1() h1a, h1b = uhf_hfc.make_h1_soc(hfcobj, dm0) h1a = numpy.asarray([reduce(numpy.dot, (orbva.T, x, orboa)) for x in h1a]) h1b = numpy.asarray([reduce(numpy.dot, (orbvb.T, x, orbob)) for x in h1b]) para = [] for n, atm_id in enumerate(hfc_nuc): nuc_gyro = get_nuc_g_factor(mol.atom_symbol(atm_id)) * nuc_mag e = numpy.einsum('xij,yij->xy', mo1a[n], h1a) * 2 e += numpy.einsum('xij,yij->xy', mo1b[n], h1b) * 2 para.append(fac * nuc_gyro * e) 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)