def project_mo_r2r(mol1, mo1, mol2): s22 = mol2.intor_symmetric('int1e_ovlp_spinor') t22 = mol2.intor_symmetric('int1e_spsp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', mol2, mol1) t21 = mole.intor_cross('int1e_spsp_spinor', mol2, mol1) n2c = s21.shape[1] pl = lib.cho_solve(s22, s21) ps = lib.cho_solve(t22, t21) return numpy.vstack((numpy.dot(pl, mo1[:n2c]), numpy.dot(ps, mo1[n2c:])))
def project_mo_r2r(mol1, mo1, mol2): s22 = mol2.intor_symmetric('cint1e_ovlp') t22 = mol2.intor_symmetric('cint1e_spsp') s21 = mole.intor_cross('cint1e_ovlp', mol2, mol1) t21 = mole.intor_cross('cint1e_spsp', mol2, mol1) n2c = s21.shape[1] pl = pyscf.lib.cho_solve(s22, s21) ps = pyscf.lib.cho_solve(t22, t21) return numpy.vstack((numpy.dot(pl, mo1[:n2c]), numpy.dot(ps, mo1[n2c:])))
def project_dm_r2r(mol1, dm1, mol2): s22 = mol2.intor_symmetric('int1e_ovlp_spinor') t22 = mol2.intor_symmetric('int1e_spsp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', mol2, mol1) t21 = mole.intor_cross('int1e_spsp_spinor', mol2, mol1) pl = lib.cho_solve(s22, s21, strict_sym_pos=False) ps = lib.cho_solve(t22, t21, strict_sym_pos=False) p21 = scipy.linalg.block_diag(pl, ps) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def project_mo_r2r(mol1, mo1, mol2): s22 = mol2.intor_symmetric('int1e_ovlp_spinor') t22 = mol2.intor_symmetric('int1e_spsp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', mol2, mol1) t21 = mole.intor_cross('int1e_spsp_spinor', mol2, mol1) n2c = s21.shape[1] pl = lib.cho_solve(s22, s21, strict_sym_pos=False) ps = lib.cho_solve(t22, t21, strict_sym_pos=False) if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: return numpy.vstack((numpy.dot(pl, mo1[:n2c]), numpy.dot(ps, mo1[n2c:]))) else: return [numpy.vstack((numpy.dot(pl, x[:n2c]), numpy.dot(ps, x[n2c:]))) for x in mo1]
def project_dm_r2r(mol1, dm1, mol2): __doc__ = project_dm_nr2nr.__doc__ s22 = mol2.intor_symmetric('int1e_ovlp_spinor') t22 = mol2.intor_symmetric('int1e_spsp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', mol2, mol1) t21 = mole.intor_cross('int1e_spsp_spinor', mol2, mol1) n2c = s21.shape[1] pl = lib.cho_solve(s22, s21) ps = lib.cho_solve(t22, t21) p21 = scipy.linalg.block_diag(pl, ps) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def project_dm_nr2nr(mol1, dm1, mol2): r''' Project density matrix representation from basis set 1 (mol1) to basis set 2 (mol2). .. math:: |AO2\rangle DM_AO2 \langle AO2| = |AO2\rangle P DM_AO1 P \langle AO2| DM_AO2 = P DM_AO1 P P = S_{AO2}^{-1}\langle AO2|AO1\rangle There are three relevant functions: :func:`project_dm_nr2nr` is the projection for non-relativistic (scalar) basis. :func:`project_dm_nr2r` projects from non-relativistic to relativistic basis. :func:`project_dm_r2r` is the projection between relativistic (spinor) basis. ''' s22 = mol2.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', mol2, mol1) p21 = lib.cho_solve(s22, s21) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def project_mo_r2r(mol1, mo1, mol2): __doc__ = project_mo_nr2nr.__doc__ s22 = mol2.intor_symmetric('int1e_ovlp_spinor') t22 = mol2.intor_symmetric('int1e_spsp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', mol2, mol1) t21 = mole.intor_cross('int1e_spsp_spinor', mol2, mol1) n2c = s21.shape[1] pl = lib.cho_solve(s22, s21) ps = lib.cho_solve(t22, t21) if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: return numpy.vstack((numpy.dot(pl, mo1[:n2c]), numpy.dot(ps, mo1[n2c:]))) else: return [numpy.vstack((numpy.dot(pl, x[:n2c]), numpy.dot(ps, x[n2c:]))) for x in mo1]
def get_hcore(self, mol=None): if mol is None: mol = self.mol xmol, contr_coeff = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert('1E' in self.approx.upper()) t = xmol.intor_symmetric('cint1e_kin_sph') v = xmol.intor_symmetric('cint1e_nuc_sph') s = xmol.intor_symmetric('cint1e_ovlp_sph') w = xmol.intor_symmetric('cint1e_pnucp_sph') if 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_nr_by_atom() nao = xmol.nao_nr() x = numpy.zeros((nao,nao)) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) t1 = xmol.intor('cint1e_kin_sph', shls_slice=shls_slice) v1 = xmol.intor('cint1e_nuc_sph', shls_slice=shls_slice) s1 = xmol.intor('cint1e_ovlp_sph', shls_slice=shls_slice) w1 = xmol.intor('cint1e_pnucp_sph', shls_slice=shls_slice) x[p0:p1,p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('cint1e_ovlp_sph') s21 = mole.intor_cross('cint1e_ovlp_sph', xmol, mol) c = lib.cho_solve(s22, s21) h1 = reduce(numpy.dot, (c.T, h1, c)) if self.xuncontract and contr_coeff is not None: h1 = reduce(numpy.dot, (contr_coeff.T, h1, contr_coeff)) return h1
def project_mo_nr2nr(mol1, mo1, mol2): r''' Project orbital coefficients from basis set 1 (C1 for mol1) to basis set 2 (C2 for mol2). .. math:: |\psi1\rangle = |AO1\rangle C1 |\psi2\rangle = P |\psi1\rangle = |AO2\rangle S^{-1}\langle AO2| AO1\rangle> C1 = |AO2\rangle> C2 C2 = S^{-1}\langle AO2|AO1\rangle C1 There are three relevant functions: :func:`project_mo_nr2nr` is the projection for non-relativistic (scalar) basis. :func:`project_mo_nr2r` projects from non-relativistic to relativistic basis. :func:`project_mo_r2r` is the projection between relativistic (spinor) basis. ''' s22 = mol2.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', mol2, mol1) if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: return lib.cho_solve(s22, numpy.dot(s21, mo1), strict_sym_pos=False) else: return [ lib.cho_solve(s22, numpy.dot(s21, x), strict_sym_pos=False) for x in mo1 ]
def picture_change(self, even_operator=(None, None), odd_operator=None): '''Picture change for even_operator + odd_operator even_operator has two terms at diagonal blocks [ v 0 ] [ 0 w ] odd_operator has the term at off-diagonal blocks [ 0 p ] [ p^T 0 ] v, w, and p can be strings (integral name) or matrices. ''' mol = self.mol xmol, contr_coeff_nr = self.get_xmol(mol) pc_mat = self._picture_change(xmol, even_operator, odd_operator) if self.basis is not None: s22 = xmol.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', xmol, mol) c = lib.cho_solve(s22, s21) elif self.xuncontract: np, nc = contr_coeff_nr.shape c = numpy.zeros((np * 2, nc * 2)) c[0::2, 0::2] = contr_coeff_nr c[1::2, 1::2] = contr_coeff_nr else: return pc_mat if pc_mat.ndim == 2: return lib.einsum('pi,pq,qj->ij', c.conj(), pc_mat, c) else: return lib.einsum('pi,xpq,qj->xij', c.conj(), pc_mat, c)
def get_hcore(self, mol=None): if mol is None: mol = self.mol xmol, contr_coeff = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert ('1E' in self.approx.upper()) t = xmol.intor_symmetric('cint1e_kin_sph') v = xmol.intor_symmetric('cint1e_nuc_sph') s = xmol.intor_symmetric('cint1e_ovlp_sph') w = xmol.intor_symmetric('cint1e_pnucp_sph') if 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_nr_by_atom() nao = xmol.nao_nr() x = numpy.zeros((nao, nao)) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) t1 = xmol.intor('cint1e_kin_sph', shls_slice=shls_slice) v1 = xmol.intor('cint1e_nuc_sph', shls_slice=shls_slice) s1 = xmol.intor('cint1e_ovlp_sph', shls_slice=shls_slice) w1 = xmol.intor('cint1e_pnucp_sph', shls_slice=shls_slice) x[p0:p1, p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('cint1e_ovlp_sph') s21 = mole.intor_cross('cint1e_ovlp_sph', xmol, mol) c = lib.cho_solve(s22, s21) h1 = reduce(numpy.dot, (c.T, h1, c)) if self.xuncontract and contr_coeff is not None: h1 = reduce(numpy.dot, (contr_coeff.T, h1, contr_coeff)) return h1
def project_mo_nr2r(mol1, mo1, mol2): s22 = mol2.intor_symmetric('cint1e_ovlp') s21 = mole.intor_cross('cint1e_ovlp_sph', mol2, mol1) ua, ub = symm.cg.real2spinor_whole(mol2) s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H mo2 = numpy.dot(s21, mo1) return numpy.linalg.solve(s22, mo2)
def project_mo_nr2r(mol1, mo1, mol2): s22 = mol2.intor_symmetric('cint1e_ovlp') s21 = mole.intor_cross('cint1e_ovlp_sph', mol2, mol1) ua, ub = symm.cg.real2spinor_whole(mol2) s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H mo2 = numpy.dot(s21, mo1) return pyscf.lib.cho_solve(s22, mo2)
def get_hcore(self, mol=None): '''2-component X2c Foldy-Wouthuysen (FW) Hamiltonian (including spin-free and spin-dependent terms) in the j-adapted spinor basis. ''' if mol is None: mol = self.mol if mol.has_ecp(): raise NotImplementedError xmol, contr_coeff_nr = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert ('1E' in self.approx.upper()) s = xmol.intor_symmetric('int1e_ovlp_spinor') t = xmol.intor_symmetric('int1e_spsp_spinor') * .5 v = xmol.intor_symmetric('int1e_nuc_spinor') w = xmol.intor_symmetric('int1e_spnucsp_spinor') if 'get_xmat' in self.__dict__: # If the get_xmat method is overwritten by user, build the X # matrix with the external get_xmat method x = self.get_xmat(xmol) h1 = _get_hcore_fw(t, v, w, s, x, c) elif 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_2c_by_atom() n2c = xmol.nao_2c() x = numpy.zeros((n2c, n2c), dtype=numpy.complex) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) s1 = xmol.intor('int1e_ovlp_spinor', shls_slice=shls_slice) t1 = xmol.intor('int1e_spsp_spinor', shls_slice=shls_slice) * .5 with xmol.with_rinv_at_nucleus(ia): z = -xmol.atom_charge(ia) v1 = z * xmol.intor('int1e_rinv_spinor', shls_slice=shls_slice) w1 = z * xmol.intor('int1e_sprinvsp_spinor', shls_slice=shls_slice) x[p0:p1, p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', xmol, mol) c = lib.cho_solve(s22, s21) h1 = reduce(numpy.dot, (c.T.conj(), h1, c)) elif self.xuncontract: np, nc = contr_coeff_nr.shape contr_coeff = numpy.zeros((np * 2, nc * 2)) contr_coeff[0::2, 0::2] = contr_coeff_nr contr_coeff[1::2, 1::2] = contr_coeff_nr h1 = reduce(numpy.dot, (contr_coeff.T.conj(), h1, contr_coeff)) return h1
def get_hcore(self, mol=None): if mol is None: mol = self.mol if mol.has_ecp(): raise NotImplementedError xmol, contr_coeff = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert ('1E' in self.approx.upper()) t = _block_diag(xmol.intor_symmetric('int1e_kin')) v = _block_diag(xmol.intor_symmetric('int1e_nuc')) s = _block_diag(xmol.intor_symmetric('int1e_ovlp')) w = _sigma_dot(xmol.intor('int1e_spnucsp')) if 'get_xmat' in self.__dict__: # If the get_xmat method is overwritten by user, build the X # matrix with the external get_xmat method x = self.get_xmat(xmol) h1 = _get_hcore_fw(t, v, w, s, x, c) elif 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_nr_by_atom() # spin-orbital basis is twice the size of NR basis atom_slices[:, 2:] *= 2 nao = xmol.nao_nr() * 2 x = numpy.zeros((nao, nao)) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) t1 = _block_diag(xmol.intor('int1e_kin', shls_slice=shls_slice)) s1 = _block_diag( xmol.intor('int1e_ovlp', shls_slice=shls_slice)) with xmol.with_rinv_at_nucleus(ia): z = -xmol.atom_charge(ia) v1 = _block_diag( z * xmol.intor('int1e_rinv', shls_slice=shls_slice)) w1 = _sigma_dot( z * xmol.intor('int1e_sprinvsp', shls_slice=shls_slice)) x[p0:p1, p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', xmol, mol) c = _block_diag(lib.cho_solve(s22, s21)) h1 = reduce(lib.dot, (c.T, h1, c)) if self.xuncontract and contr_coeff is not None: contr_coeff = _block_diag(contr_coeff) h1 = reduce(lib.dot, (contr_coeff.T, h1, contr_coeff)) return h1
def project_mo_nr2nr(mol1, mo1, mol2): r''' Project orbital coefficients .. math:: |\psi1> = |AO1> C1 |\psi2> = P |\psi1> = |AO2>S^{-1}<AO2| AO1> C1 = |AO2> C2 C2 = S^{-1}<AO2|AO1> C1 ''' s22 = mol2.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', mol2, mol1) return lib.cho_solve(s22, numpy.dot(s21, mo1))
def project_dm_nr2r(mol1, dm1, mol2): assert(not mol1.cart) s22 = mol2.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_sph', mol2, mol1) ua, ub = mol2.sph2spinor_coeff() s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H p21 = lib.cho_solve(s22, s21, strict_sym_pos=False) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def project_mo_nr2nr(mol1, mo1, mol2): r''' Project orbital coefficients .. math:: |\psi1> = |AO1> C1 |\psi2> = P |\psi1> = |AO2>S^{-1}<AO2| AO1> C1 = |AO2> C2 C2 = S^{-1}<AO2|AO1> C1 ''' s22 = mol2.intor_symmetric('cint1e_ovlp_sph') s21 = mole.intor_cross('cint1e_ovlp_sph', mol2, mol1) return numpy.linalg.solve(s22, numpy.dot(s21, mo1))
def project_mo_nr2r(mol1, mo1, mol2): assert(not mol1.cart) s22 = mol2.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_sph', mol2, mol1) ua, ub = mol2.sph2spinor_coeff() s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: mo2 = numpy.dot(s21, mo1) return lib.cho_solve(s22, mo2, strict_sym_pos=False) else: return [lib.cho_solve(s22, numpy.dot(s21, x), strict_sym_pos=False) for x in mo1]
def project_mo_nr2r(mol1, mo1, mol2): __doc__ = project_mo_nr2nr.__doc__ assert(not mol1.cart) s22 = mol2.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_sph', mol2, mol1) ua, ub = mol2.sph2spinor_coeff() s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: mo2 = numpy.dot(s21, mo1) return lib.cho_solve(s22, mo2) else: return [lib.cho_solve(s22, numpy.dot(s21, x)) for x in mo1]
def project_dm_nr2r(mol1, dm1, mol2): __doc__ = project_dm_nr2nr.__doc__ assert(not mol1.cart) s22 = mol2.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_sph', mol2, mol1) ua, ub = mol2.sph2spinor_coeff() s21 = numpy.dot(ua.T.conj(), s21) + numpy.dot(ub.T.conj(), s21) # (*) # mo2: alpha, beta have been summed in Eq. (*) # so DM = mo2[:,:nocc] * 1 * mo2[:,:nocc].H p21 = lib.cho_solve(s22, s21) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def get_hcore(self, mol=None): '''2-component X2c hcore Hamiltonian (including spin-free and spin-dependent terms) in the j-adapted spinor basis. ''' if mol is None: mol = self.mol xmol, contr_coeff_nr = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert ('1E' in self.approx.upper()) s = xmol.intor_symmetric('int1e_ovlp_spinor') t = xmol.intor_symmetric('int1e_spsp_spinor') * .5 v = xmol.intor_symmetric('int1e_nuc_spinor') w = xmol.intor_symmetric('int1e_spnucsp_spinor') if 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_2c_by_atom() n2c = xmol.nao_2c() x = numpy.zeros((n2c, n2c), dtype=numpy.complex) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) s1 = xmol.intor('int1e_ovlp_spinor', shls_slice=shls_slice) t1 = xmol.intor('int1e_spsp_spinor', shls_slice=shls_slice) * .5 v1 = xmol.intor('int1e_nuc_spinor', shls_slice=shls_slice) w1 = xmol.intor('int1e_spnucsp_spinor', shls_slice=shls_slice) x[p0:p1, p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('int1e_ovlp_spinor') s21 = mole.intor_cross('int1e_ovlp_spinor', xmol, mol) c = lib.cho_solve(s22, s21) h1 = reduce(numpy.dot, (c.T.conj(), h1, c)) elif self.xuncontract: np, nc = contr_coeff_nr.shape contr_coeff = numpy.zeros((np * 2, nc * 2)) contr_coeff[0::2, 0::2] = contr_coeff_nr contr_coeff[1::2, 1::2] = contr_coeff_nr h1 = reduce(numpy.dot, (contr_coeff.T.conj(), h1, contr_coeff)) return h1
def picture_change(self, even_operator=(None, None), odd_operator=None): mol = self.mol xmol, c = self.get_xmol(mol) pc_mat = self._picture_change(xmol, even_operator, odd_operator) if self.basis is not None: s22 = xmol.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', xmol, mol) c = lib.cho_solve(s22, s21) elif self.xuncontract: pass else: return pc_mat c = _block_diag(c) if pc_mat.ndim == 2: return lib.einsum('pi,pq,qj->ij', c, pc_mat, c) else: return lib.einsum('pi,xpq,qj->xij', c, pc_mat, c)
def project_mo_nr2nr(mol1, mo1, mol2): r''' Project orbital coefficients from basis set 1 (C1 for mol1) to basis set 2 (C2 for mol2). .. math:: |\psi1\rangle = |AO1\rangle C1 |\psi2\rangle = P |\psi1\rangle = |AO2\rangle S^{-1}\langle AO2| AO1\rangle> C1 = |AO2\rangle> C2 C2 = S^{-1}\langle AO2|AO1\rangle C1 There are three relevant functions: :func:`project_mo_nr2nr` is the projection for non-relativistic (scalar) basis. :func:`project_mo_nr2r` projects from non-relativistic to relativistic basis. :func:`project_mo_r2r` is the projection between relativistic (spinor) basis. ''' s22 = mol2.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', mol2, mol1) if isinstance(mo1, numpy.ndarray) and mo1.ndim == 2: return lib.cho_solve(s22, numpy.dot(s21, mo1)) else: return [lib.cho_solve(s22, numpy.dot(s21, x)) for x in mo1]
def get_hcore(self, mol=None): if mol is None: mol = self.mol xmol, contr_coeff_nr = self.get_xmol(mol) c = lib.param.LIGHT_SPEED assert('1E' in self.approx.upper()) s = xmol.intor_symmetric('cint1e_ovlp') t = xmol.intor_symmetric('cint1e_spsp') * .5 v = xmol.intor_symmetric('cint1e_nuc') w = xmol.intor_symmetric('cint1e_spnucsp') if 'ATOM' in self.approx.upper(): atom_slices = xmol.offset_2c_by_atom() n2c = xmol.nao_2c() x = numpy.zeros((n2c,n2c), dtype=numpy.complex) for ia in range(xmol.natm): ish0, ish1, p0, p1 = atom_slices[ia] shls_slice = (ish0, ish1, ish0, ish1) s1 = xmol.intor('cint1e_ovlp', shls_slice=shls_slice) t1 = xmol.intor('cint1e_spsp', shls_slice=shls_slice) * .5 v1 = xmol.intor('cint1e_nuc', shls_slice=shls_slice) w1 = xmol.intor('cint1e_spnucsp', shls_slice=shls_slice) x[p0:p1,p0:p1] = _x2c1e_xmatrix(t1, v1, w1, s1, c) h1 = _get_hcore_fw(t, v, w, s, x, c) else: h1 = _x2c1e_get_hcore(t, v, w, s, c) if self.basis is not None: s22 = xmol.intor_symmetric('cint1e_ovlp') s21 = mole.intor_cross('cint1e_ovlp', xmol, mol) c = lib.cho_solve(s22, s21) h1 = reduce(numpy.dot, (c.T.conj(), h1, c)) elif self.xuncontract: np, nc = contr_coeff_nr.shape contr_coeff = numpy.zeros((np*2,nc*2)) contr_coeff[0::2,0::2] = contr_coeff_nr contr_coeff[1::2,1::2] = contr_coeff_nr h1 = reduce(numpy.dot, (contr_coeff.T.conj(), h1, contr_coeff)) return h1
def project_mo_nr2nr(mol1, mo1, mol2): s22 = mol2.intor_symmetric('cint1e_ovlp_sph') s21 = mole.intor_cross('cint1e_ovlp_sph', mol2, mol1) return numpy.linalg.solve(s22, numpy.dot(s21, mo1))
def MakeActiveSpace(mol,mf): np.set_printoptions(precision=4,linewidth=10000,edgeitems=3,suppress=False) # PiAtoms list contains the set of main-group atoms involved in the pi-system # indices are 1-based. Anthracene = [28,29,30,32, 34,36,38, 39,40,41, 43,45,47,49] Phenol = [1,7,9,10,12,14,15] Pyridine = [3,16,17,19,20,22] mol2=mol.copy() mol2.basis = 'MINAO' mol2.build() # make a minimal AO basis for our atoms. We load the basis from a library # just to have access to its shell-composition. Need that to find the indices # of all atoms, and the AO indices of the px/py/pz functions. Elements,Coords = Atoms_w_Coords(mol2) Shells = MakeShells(mol2,Elements) #====================This function is used when #1) you study reactions and # of electrons is changing for some atoms in your pi-systems; #2) you have O or N atoms which can have different number of electrons in different molecules, then you might want to specify # of electrons to make sure the total number is even #3) you have a charge on your pi-system. For ferrocene you should assign one more electron to one of C in your pi-systems def AssignTag(Elements,iAt, Element, Tag): assert(Elements[iAt-1] == Element) Elements[iAt-1]= Element+Tag # fix type of atom for the donor-acceptor which are exchanging the hydrogens. # During the process, the hydrogens are moving and the Huckel-Theory # formal number of contributed pi-electrons may change. # These settings override the auto-detection of number of pi electrons # based on atomic connectivity in GetNumPiElec() below. AssignTag(Elements,3, "N", "1e") AssignTag(Elements,1, "O", "2e") Elements =np.asarray(Elements) OrbBasis=mol.basis C = mf.mo_coeff S1=mol.intor_symmetric("cint1e_ovlp_sph") S2=mol2.intor_symmetric("cint1e_ovlp_sph") S12 = mole.intor_cross('cint1e_ovlp_sph', mol, mol2) SMo = mdot(C.T, S1, C) print (" MO deviation from orthogonality {:8.2e} \n".format(rmsd(SMo - np.eye(SMo.shape[0])))) # make arrays of occupation numbers and orbital eigenvalues. Occ = mf.mo_occ Eps = mf.mo_energy nOrb = C.shape[1] if (mol.spin==0): nOcc = np.sum(Occ == 2) else: nOcc = np.sum(Occ == 2)+np.sum(Occ == 1) n1=np.sum(Occ == 1) print (" Number of singly occupied orbitals {} ".format(n1)) nVir = np.sum(Occ == 0) assert(nOcc + nVir == nOrb) print (" Number of occupied orbitals {} ".format(nOcc)) print (" Number of unoccupied orbitals {} ".format(nVir)) # Compute Fock matrix from orbital eigenvalues (SCF has to be fully converged) Fock = mdot(S1, C, np.diag(Eps), C.T, S1.T) Rdm = mdot(C, np.diag(Occ), C.T) COcc = C[:,:nOcc] CVir = C[:,nOcc:] Smh1 = MakeSmh(S1) Sh1 = np.dot(S1, Smh1) # Compute IAO basis (non-orthogonal). Will be used to identify the # pi-MO-space of the target atom groups. CIb = MakeIaosRaw(COcc, S1, S2, S12) CIbOcc = np.linalg.lstsq(CIb, COcc)[0] Err = np.dot(Sh1, np.dot(CIb, CIbOcc) - COcc) # check orthogonality of IAO basis occupied orbitals SIb = mdot(CIb.T, S1, CIb) SIbOcc = mdot(CIbOcc.T, SIb, CIbOcc) nIb = SIb.shape[0] if 0: # make the a representation of the virtual valence space. SmhIb = MakeSmh(SIb) nIbVir = nIb - nOcc # number of virtual valence orbitals CTargetIb = CIb STargetIb = mdot(CTargetIb.T, S1, CTargetIb) SmhTargetIb = MakeSmh(STargetIb) STargetIbVir = mdot(SmhTargetIb, CTargetIb.T, S1, CVir) U,sig,Vt = np.linalg.svd(STargetIbVir, full_matrices=False) print (" Number of target MINAO basis fn {}\n".format(CTargetIb.shape[1])) print("SIbVir Singular Values (n={})".format(len(sig))) print(" [{}]".format(', '.join('{:.4f}'.format(k) for k in sig))) assert(np.abs(sig[nIbVir-1] - 1.0) < 1e-4) assert(np.abs(sig[nIbVir] - 0.0) < 1e-4) # for pi systems: do it like here -^ for the virtuals, but # for COcc and CVir both. What we should do is: # - instead of CIb, we use CTargetIb = CIb * (AO-linear-comb-matrix) # - instead of SmhIb, we use its corresponding target-AO overlap matrix: # SmhTargetIb = MakeSmh(mdot(CTargetIb.T, S1, CTargetIb)) # - instead of using nOcc/nVir/nIb to determine the target number # of orbitals, we obtain the target number of pi electrons by counting # their subset from the selected main group atoms (see CHEM 408 u11). # From this determine the number of occupied pi-orbitals this system # is supposed to have, and virtual orbitals as nTargetIb - nPiOcc # The AoMix matrix is made from the pi-system's inertial tensor to get the # local z-direction, and then linearly-combining this onto the highest-N p-AOs. CActOcc = [] CActVir = [] # add two pi-HOMOs and two pi-LUMOs from anthracene CFragOcc, CFragVir,OccOrbExpected,nVirtOrbExpected, = MakePiSystemOrbitals("Antracene-Fragment", Anthracene, None, Elements,Coords, CIb, Shells, S1, S12, S2, Fock, COcc, CVir) CActOcc.append(CFragOcc[:,-2]) CActOcc.append(CFragOcc[:,-1]) CActVir.append(CFragVir[:,0]) CActVir.append(CFragVir[:,1]) # add two pi-HOMOs and two pi-LUMOs from phenol CFragOcc, CFragVir,nOccOrbExpected,nVirtOrbExpected = MakePiSystemOrbitals("Phenol-Fragment", Phenol, None, Elements,Coords, CIb, Shells, S1, S12, S2, Fock, COcc, CVir) CActOcc.append(CFragOcc[:,-2]) CActOcc.append(CFragOcc[:,-1]) CActVir.append(CFragVir[:,0]) CActVir.append(CFragVir[:,1]) # add two pi-HOMOs and two pi-LUMOs from pyridine CFragOcc, CFragVir,nOccOrbExpected,nVirtOrbExpected = MakePiSystemOrbitals("Pyridine", Pyridine, None, Elements,Coords, CIb, Shells, S1, S12, S2, Fock, COcc, CVir) CActOcc.append(CFragOcc[:,-2]) CActOcc.append(CFragOcc[:,-1]) CActVir.append(CFragVir[:,0]) CActVir.append(CFragVir[:,1]) nActOcc = len(CActOcc) nActVir = len(CActVir) print("\n -- Joining active spaces") if (mol.spin==0): nElec = 2*len(CActOcc) else: nElec = 2*len(CActOcc)-n1 CAct = np.array(CActOcc + CActVir).T if 0: # orthogonalize and semi-canonicalize SAct = mdot(CAct.T, S1, CAct) ew, ev = np.linalg.eigh(SAct) print(" CAct initial overlap (if all ~approx 1, then the initial active orbitals are near-orthogonal. That is good.)") print(" [{}]".format(', '.join('{:.4f}'.format(k) for k in ew))) CAct = np.dot(CAct, MakeSmh(SAct)) CAct = SemiCanonicalize(CAct, Fock, S1, "active") print (" Number of Active Electrons {} ".format(nElec)) print (" Number of Active Orbitals {} ".format( CAct.shape[1])) # make new non-active occupied and non-active virtual orbitals, # in order to rebuild a full MO matrix. def MakeInactiveSpace(Name, CActList, COrb1): CAct = np.array(CActList).T SAct = mdot(CAct.T, S1, CAct) CAct = np.dot(CAct, MakeSmh(SAct)) SActMo = mdot(COrb1.T, S1.T, CAct, CAct.T, S1, COrb1) ew, ev = np.linalg.eigh(SActMo) # small ews first (orbs not overlapping with active orbs). nRest = COrb1.shape[1] - CAct.shape[1] if 0: for i in range(len(ew)): print("{:4} {:15.6f} {}".format(i,ew[i], i == nRest)) assert(np.abs(ew[nRest-1] - 0.0) < 1e-8) assert(np.abs(ew[nRest] - 1.0) < 1e-8) CNewOrb1 = np.dot(COrb1, ev[:,:nRest]) return SemiCanonicalize(CNewOrb1, Fock, S1, Name, Print=False) CNewClo = MakeInactiveSpace("NewClo", CActOcc, COcc) CNewExt = MakeInactiveSpace("NewVir", CActVir, CVir) nNewClo = CNewClo.shape[1] nNewExt = CNewExt.shape[1] # re-orthogonalize (should be orthogonal already, but just to be sure). COrbNew = np.hstack([CAct]) if 1: COrbNew = np.hstack([CNewClo, CAct, CNewExt]) SMo = mdot(COrbNew.T, S1, COrbNew) COrbNew = np.dot(COrbNew, MakeSmh(SMo)) print (" Number of Core Orbitals {} ".format(CNewClo.shape[1])) print (" Number of Virtual Orbitals {} ".format(CNewExt.shape[1])) print (" Total Number of Orbitals {} ".format(COrbNew.shape[1])) return CNewClo.shape[1],CAct.shape[1],CNewExt.shape[1],nElec, COrbNew