def init_guess(self, mf, nstates=None, wfnsym=None): if nstates is None: nstates = self.nstates if wfnsym is None: wfnsym = self.wfnsym mo_energy = mf.mo_energy mo_occ = mf.mo_occ occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] e_ia = mo_energy[viridx] - mo_energy[occidx, None] e_ia_max = e_ia.max() if wfnsym is not None and mf.mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mf.mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mf.mol, mf.mo_coeff) orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps e_ia[(orbsym_in_d2h[occidx, None] ^ orbsym_in_d2h[viridx]) != wfnsym] = 1e99 nov = e_ia.size nstates = min(nstates, nov) e_ia = e_ia.ravel() e_threshold = min(e_ia_max, e_ia[numpy.argsort(e_ia)[nstates - 1]]) # Handle degeneracy, include all degenerated states in initial guess e_threshold += 1e-6 idx = numpy.where(e_ia <= e_threshold)[0] x0 = numpy.zeros((idx.size, nov)) for i, j in enumerate(idx): x0[i, j] = 1 # Koopmans' excitations return x0
def init_guess(self, mf, nstates=None, wfnsym=None): if nstates is None: nstates = self.nstates if wfnsym is None: wfnsym = self.wfnsym mo_energy = mf.mo_energy mo_occ = mf.mo_occ occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] e_ia = mo_energy[viridx] - mo_energy[occidx, None] if wfnsym is not None and mf.mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mf.mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mf.mol, mf.mo_coeff) orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps e_ia[(orbsym_in_d2h[occidx, None] ^ orbsym_in_d2h[viridx]) != wfnsym] = 1e99 nov = e_ia.size nroot = min(nstates, nov) x0 = numpy.zeros((nroot, nov)) idx = numpy.argsort(e_ia.ravel()) for i in range(nroot): x0[i, idx[i]] = 1 # Koopmans' excitations return x0
def init_guess(self, mf, nstates=None, wfnsym=None): if nstates is None: nstates = self.nstates if wfnsym is None: wfnsym = self.wfnsym mol = mf.mol mo_energy = mf.mo_energy mo_occ = mf.mo_occ occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mf.mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 e_ia_a[(orbsyma[occidxa, None] ^ orbsyma[viridxa]) != wfnsym] = 1e99 e_ia_b[(orbsymb[occidxb, None] ^ orbsymb[viridxb]) != wfnsym] = 1e99 e_ia = numpy.hstack((e_ia_a.ravel(), e_ia_b.ravel())) nov = e_ia.size nroot = min(nstates, nov) x0 = numpy.zeros((nroot, nov)) idx = numpy.argsort(e_ia) for i in range(nroot): x0[i, idx[i]] = 1 # lowest excitations return x0
def _id_wfnsym(cis, norb, nelec, orbsym, wfnsym): if wfnsym is None: neleca, nelecb = _unpack_nelec(nelec) wfnsym = 0 # Ag, A1 or A for i in orbsym[nelecb:neleca]: wfnsym ^= i elif isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(cis.mol.groupname, wfnsym) return wfnsym % 10
def _id_wfnsym(cis, norb, nelec, wfnsym): if wfnsym is None: neleca, nelecb = direct_spin1._unpack_nelec(nelec) wfnsym = 0 # Ag, A1 or A for i in cis.orbsym[nelecb:neleca]: wfnsym ^= i elif isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(cis.mol.groupname, wfnsym) % 10 return wfnsym
def gen_vind(self, mf=None): if mf is None: mf = self._scf wfnsym = self.wfnsym mol = mf.mol mo_coeff = mf.mo_coeff assert mo_coeff.dtype == numpy.double mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 1)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = ghf_symm.get_orbsym(mol, mo_coeff) orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps sym_forbid = (orbsym_in_d2h[occidx, None] ^ orbsym_in_d2h[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1, 1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia) ed_ia = e_ia * d_ia hdiag = e_ia.ravel()**2 vresp = mf.gen_response(mo_coeff, mo_occ, hermi=1) def vind(zs): zs = numpy.asarray(zs).reshape(-1, nocc, nvir) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 dmov = lib.einsum('xov,po,qv->xpq', zs * d_ia, orbo, orbv) # +cc for A+B because K_{ai,jb} in A == K_{ai,bj} in B dmov = dmov + dmov.transpose(0, 2, 1) v1ao = vresp(dmov) v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo, orbv) # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov += numpy.einsum('xov,ov->xov', zs, ed_ia) v1ov *= d_ia if wfnsym is not None and mol.symmetry: v1ov[:, sym_forbid] = 0 return v1ov.reshape(v1ov.shape[0], -1) return vind, hdiag
def _id_wfnsym(cisolver, norb, nelec, orbsym, wfnsym): '''Guess wfnsym or convert wfnsym to symmetry ID if it's a symmetry label''' if wfnsym is None: neleca, nelecb = _unpack_nelec(nelec) wfnsym = 0 # Ag, A1 or A for i in orbsym[nelecb:neleca]: wfnsym ^= i elif isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(cisolver.mol.groupname, wfnsym) return wfnsym % 10
def gen_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx, None] ^ orbsym[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1, 1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel()**2 vresp = _gen_rhf_response(mf, singlet=singlet, hermi=1) def vind(zs): nz = len(zs) dmov = numpy.empty((nz, nao, nao)) for i, z in enumerate(zs): # *2 for double occupancy dm = reduce(numpy.dot, (orbo, (d_ia * z).reshape(nocc, nvir) * 2, orbv.T)) dmov[ i] = dm + dm.T # +cc for A+B and K_{ai,jb} in A == K_{ai,bj} in B v1ao = vresp(dmov) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0, nocc, nocc, nmo)).reshape(-1, nocc * nvir) for i, z in enumerate(zs): # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov[i] += ed_ia * z v1ov[i] *= d_ia return v1ov.reshape(nz, -1) return vind, hdiag
def _id_wfnsym(cis, norb, nelec, wfnsym): if wfnsym is None: if isinstance(nelec, (int, numpy.number)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec wfnsym = 0 # Ag, A1 or A for i in cis.orbsym[nelecb:neleca]: wfnsym ^= i elif isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(cis.mol.groupname, wfnsym) % 10 return wfnsym
def _id_wfnsym(cis, norb, nelec, wfnsym): if wfnsym is None: if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec wfnsym = 0 # Ag, A1 or A for i in cis.orbsym[nelecb:neleca]: wfnsym ^= i elif isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(cis.mol.groupname, wfnsym) % 10 return wfnsym
def gen_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx, None] ^ orbsym[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1, 1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia) ed_ia = e_ia * d_ia hdiag = e_ia.ravel()**2 vresp = mf.gen_response(singlet=singlet, hermi=1) def vind(zs): zs = numpy.asarray(zs).reshape(-1, nocc, nvir) # *2 for double occupancy dmov = lib.einsum('xov,ov,po,qv->xpq', zs, d_ia * 2, orbo, orbv.conj()) # +cc for A+B and K_{ai,jb} in A == K_{ai,bj} in B dmov = dmov + dmov.conj().transpose(0, 2, 1) v1ao = vresp(dmov) v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo.conj(), orbv) # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov += numpy.einsum('xov,ov->xov', zs, ed_ia) v1ov *= d_ia return v1ov.reshape(v1ov.shape[0], -1) return vind, hdiag
def gen_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1,1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel() ** 2 vresp = _gen_rhf_response(mf, singlet=singlet, hermi=1) def vind(zs): nz = len(zs) dmov = numpy.empty((nz,nao,nao)) for i, z in enumerate(zs): # *2 for double occupancy dm = reduce(numpy.dot, (orbo, (d_ia*z).reshape(nocc,nvir)*2, orbv.T)) dmov[i] = dm + dm.T # +cc for A+B and K_{ai,jb} in A == K_{ai,bj} in B v1ao = vresp(dmov) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc*nvir) for i, z in enumerate(zs): # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov[i] += ed_ia*z v1ov[i] *= d_ia return v1ov.reshape(nz,-1) return vind, hdiag
def check_transformer_cache(self): assert (isinstance(self.smult, (int, np.number))) neleca, nelecb = _unpack_nelec(self.nelec) if isinstance(self.wfnsym, str): wfnsym = symm.irrep_name2id(self.mol.groupname, self.wfnsym) else: wfnsym = self.wfnsym if self.transformer is None: self.transformer = CSFTransformer(self.norb, neleca, nelecb, self.smult, orbsym=self.orbsym, wfnsym=wfnsym) else: self.transformer._update_spin_cache(self.norb, neleca, nelecb, self.smult) self.transformer._update_symm_cache(self.orbsym) self.transformer.wfnsym = wfnsym
def las_symm_tuple(las): # This really should be much more modular # Symmetry tuple: neleca, nelecb, irrep statesym = [] s2_states = [] for iroot in range(las.nroots): neleca = 0 nelecb = 0 wfnsym = 0 s = 0 m = [] for fcibox, nelec in zip(las.fciboxes, las.nelecas_sub): solver = fcibox.fcisolvers[iroot] na, nb = _unpack_nelec(fcibox._get_nelec(solver, nelec)) neleca += na nelecb += nb s_frag = (solver.smult - 1) // 2 s += s_frag * (s_frag + 1) m.append((na - nb) // 2) fragsym = getattr(solver, 'wfnsym', 0) or 0 # in case getattr returns "None" if isinstance(fragsym, str): fragsym = symm.irrep_name2id(solver.mol.groupname, fragsym) assert isinstance(fragsym, (int, np.integer)), '{} {}'.format( type(fragsym), fragsym) wfnsym ^= fragsym s += sum([2 * m1 * m2 for m1, m2 in combinations(m, 2)]) s2_states.append(s) statesym.append((neleca, nelecb, wfnsym)) lib.logger.info(las, 'Symmetry analysis of LAS states:') lib.logger.info( las, ' {:2s} {:>16s} {:6s} {:6s} {:6s} {:6s}'.format( 'ix', 'Energy', 'Neleca', 'Nelecb', '<S**2>', 'Wfnsym')) for ix, (e, sy, s2) in enumerate(zip(las.e_states, statesym, s2_states)): neleca, nelecb, wfnsym = sy wfnsym = symm.irrep_id2name(las.mol.groupname, wfnsym) lib.logger.info( las, ' {:2d} {:16.10f} {:6d} {:6d} {:6.3f} {:>6s}'.format( ix, e, neleca, nelecb, s2, wfnsym)) return statesym, np.asarray(s2_states)
def init_guess(self, mf, nstates=None, wfnsym=None): if nstates is None: nstates = self.nstates if wfnsym is None: wfnsym = self.wfnsym mol = mf.mol mo_energy = mf.mo_energy mo_occ = mf.mo_occ occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T e_ia_max = max(e_ia_a.max(), e_ia_b.max()) if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mf.mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma_in_d2h = numpy.asarray(orbsyma) % 10 orbsymb_in_d2h = numpy.asarray(orbsymb) % 10 e_ia_a[(orbsyma_in_d2h[occidxa, None] ^ orbsyma_in_d2h[viridxa]) != wfnsym] = 1e99 e_ia_b[(orbsymb_in_d2h[occidxb, None] ^ orbsymb_in_d2h[viridxb]) != wfnsym] = 1e99 e_ia = numpy.hstack((e_ia_a.ravel(), e_ia_b.ravel())) e_ia_max = e_ia.max() nov = e_ia.size nstates = min(nstates, nov) e_threshold = min(e_ia_max, e_ia[numpy.argsort(e_ia)[nstates - 1]]) # Handle degeneracy e_threshold += 1e-6 idx = numpy.where(e_ia <= e_threshold)[0] x0 = numpy.zeros((idx.size, nov)) for i, j in enumerate(idx): x0[i, j] = 1 # Koopmans' excitations return x0
def init_guess(self, mf, nstates=None, wfnsym=None): if nstates is None: nstates = self.nstates if wfnsym is None: wfnsym = self.wfnsym mo_energy = mf.mo_energy mo_occ = mf.mo_occ occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] e_ia = mo_energy[viridx] - mo_energy[occidx,None] if wfnsym is not None and mf.mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mf.mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mf.mol, mf.mo_coeff) % 10 e_ia[(orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym] = 1e99 nov = e_ia.size nroot = min(nstates, nov) x0 = numpy.zeros((nroot, nov)) idx = numpy.argsort(e_ia.ravel()) for i in range(nroot): x0[i,idx[i]] = 1 # Koopmans' excitations return x0
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) #fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) #foo = fock[occidx[:,None],occidx] #fvv = fock[viridx[:,None],viridx] foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag.ravel(), hdiag.ravel())) mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(xys): nz = len(xys) if wfnsym is not None and mol.symmetry: # shape(nz,2,nocc,nvir): 2 ~ X,Y xys = numpy.copy(xys).reshape(nz,2,nocc,nvir) xys[:,:,sym_forbid] = 0 dms = numpy.empty((nz,nao,nao)) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) # *2 for double occupancy dmx = reduce(numpy.dot, (orbo, x*2, orbv.T)) dmy = reduce(numpy.dot, (orbv, y.T*2, orbo.T)) dms[i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) v1vo = _ao2mo.nr_e2(v1ao, mo_coeff, (nocc,nmo,0,nocc)).reshape(-1,nvir,nocc) hx = numpy.empty((nz,2,nocc,nvir), dtype=v1ov.dtype) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) hx[i,0] = v1ov[i] hx[i,0]+= numpy.einsum('sp,qs->qp', fvv, x) # AX hx[i,0]-= numpy.einsum('sp,pr->sr', foo, x) # AX hx[i,1] =-v1vo[i].T hx[i,1]-= numpy.einsum('sp,qs->qp', fvv, y) #-AY hx[i,1]+= numpy.einsum('sp,pr->sr', foo, y) #-AY if wfnsym is not None and mol.symmetry: hx[:,:,sym_forbid] = 0 return hx.reshape(nz,-1) return vind, hdiag
def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute (A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym if fock_ao is None: #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) else: fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs).reshape(-1,nocc,nvir) zs[:,sym_forbid] = 0 dmov = numpy.empty((nz,nao,nao)) for i, z in enumerate(zs): # *2 for double occupancy dmov[i] = reduce(numpy.dot, (orbo, z.reshape(nocc,nvir)*2, orbv.conj().T)) v1ao = vresp(dmov) #v1ov = numpy.asarray([reduce(numpy.dot, (orbo.T, v, orbv)) for v in v1ao]) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) for i, z in enumerate(zs): v1ov[i]+= numpy.einsum('sp,qs->qp', fvv, z.reshape(nocc,nvir)) v1ov[i]-= numpy.einsum('sp,pr->sr', foo, z.reshape(nocc,nvir)) if wfnsym is not None and mol.symmetry: v1ov[:,sym_forbid] = 0 return v1ov.reshape(nz,-1) return vind, hdiag
def get_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0]>0)[0] occidxb = numpy.where(mo_occ[1]>0)[0] viridxa = numpy.where(mo_occ[0]==0)[0] viridxb = numpy.where(mo_occ[1]==0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:,occidxa] orbob = mo_coeff[1][:,occidxb] orbva = mo_coeff[0][:,viridxa] orbvb = mo_coeff[1][:,viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 sym_forbida = (orbsyma[occidxa,None] ^ orbsyma[viridxa]) != wfnsym sym_forbidb = (orbsymb[occidxb,None] ^ orbsymb[viridxb]) != wfnsym sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = (mo_energy[0][viridxa,None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb,None] - mo_energy[1][occidxb]).T e_ia = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel() ** 2 vresp = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:,sym_forbid] = 0 dmov = numpy.empty((2,nz,nao,nao)) for i in range(nz): z = d_ia * zs[i] za = z[:nocca*nvira].reshape(nocca,nvira) zb = z[nocca*nvira:].reshape(noccb,nvirb) dm = reduce(numpy.dot, (orboa, za, orbva.T)) dmov[0,i] = dm + dm.T dm = reduce(numpy.dot, (orbob, zb, orbvb.T)) dmov[1,i] = dm + dm.T v1ao = vresp(dmov) v1a = _ao2mo.nr_e2(v1ao[0], mo_coeff[0], (0,nocca,nocca,nmo)) v1b = _ao2mo.nr_e2(v1ao[1], mo_coeff[1], (0,noccb,noccb,nmo)) hx = numpy.hstack((v1a.reshape(nz,-1), v1b.reshape(nz,-1))) for i, z in enumerate(zs): hx[i] += ed_ia * z hx[i] *= d_ia return hx return vind, hdiag
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 sym_forbida = (orbsyma[occidxa, None] ^ orbsyma[viridxa]) != wfnsym sym_forbidb = (orbsymb[occidxb, None] ^ orbsymb[viridxb]) != wfnsym sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T e_ia = hdiag = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag.ravel(), hdiag.ravel())) mo_a = numpy.asarray(numpy.hstack((orboa, orbva)), order='F') mo_b = numpy.asarray(numpy.hstack((orbob, orbvb)), order='F') mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) vresp = _gen_uhf_response(mf, hermi=0, max_memory=max_memory) def vind(xys): nz = len(xys) if wfnsym is not None and mol.symmetry: # shape(nz,2,-1): 2 ~ X,Y xys = numpy.copy(xys).reshape(nz, 2, -1) xys[:, :, sym_forbid] = 0 dms = numpy.empty((2, nz, nao, nao)) # 2 ~ alpha,beta for i in range(nz): x, y = xys[i].reshape(2, -1) xa = x[:nocca * nvira].reshape(nocca, nvira) xb = x[nocca * nvira:].reshape(noccb, nvirb) ya = y[:nocca * nvira].reshape(nocca, nvira) yb = y[nocca * nvira:].reshape(noccb, nvirb) dmx = reduce(numpy.dot, (orboa, xa, orbva.T)) dmy = reduce(numpy.dot, (orbva, ya.T, orboa.T)) dms[0, i] = dmx + dmy # AX + BY dmx = reduce(numpy.dot, (orbob, xb, orbvb.T)) dmy = reduce(numpy.dot, (orbvb, yb.T, orbob.T)) dms[1, i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1avo = _ao2mo.nr_e2(v1ao[0], mo_a, (nocca, nmo, 0, nocca)) v1bvo = _ao2mo.nr_e2(v1ao[1], mo_b, (noccb, nmo, 0, noccb)) v1aov = _ao2mo.nr_e2(v1ao[0], mo_a, (0, nocca, nocca, nmo)) v1bov = _ao2mo.nr_e2(v1ao[1], mo_b, (0, noccb, noccb, nmo)) hx = numpy.empty((nz, 2, nvira * nocca + nvirb * noccb), dtype=v1avo.dtype) for i in range(nz): x, y = xys[i].reshape(2, -1) hx[i, 0, :nvira * nocca] = v1aov[i].ravel() hx[i, 0, nvira * nocca:] = v1bov[i].ravel() hx[i, 0] += e_ia * x # AX hx[i, 1, :nvira * nocca] = -v1avo[i].reshape(nvira, nocca).T.ravel() hx[i, 1, nvira * nocca:] = -v1bvo[i].reshape(nvirb, noccb).T.ravel() hx[i, 1] -= e_ia * y #-AY if wfnsym is not None and mol.symmetry: hx[:, :, sym_forbid] = 0 return hx.reshape(nz, -1) return vind, hdiag
def gen_tda_operation(mf, fock_ao=None, wfnsym=None): '''(A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 sym_forbida = (orbsyma[occidxa, None] ^ orbsyma[viridxa]) != wfnsym sym_forbidb = (orbsymb[occidxb, None] ^ orbsymb[viridxb]) != wfnsym sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T e_ia = hdiag = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 mo_a = numpy.asarray(numpy.hstack((orboa, orbva)), order='F') mo_b = numpy.asarray(numpy.hstack((orbob, orbvb)), order='F') mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) vresp = _gen_uhf_response(mf, hermi=0, max_memory=max_memory) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 dmov = numpy.empty((2, nz, nao, nao)) for i, z in enumerate(zs): za = z[:nocca * nvira].reshape(nocca, nvira) zb = z[nocca * nvira:].reshape(noccb, nvirb) dmov[0, i] = reduce(numpy.dot, (orboa, za, orbva.conj().T)) dmov[1, i] = reduce(numpy.dot, (orbob, zb, orbvb.conj().T)) v1ao = vresp(dmov) v1a = _ao2mo.nr_e2(v1ao[0], mo_a, (0, nocca, nocca, nmo)).reshape(-1, nocca, nvira) v1b = _ao2mo.nr_e2(v1ao[1], mo_b, (0, noccb, noccb, nmo)).reshape(-1, noccb, nvirb) for i, z in enumerate(zs): za = z[:nocca * nvira].reshape(nocca, nvira) zb = z[nocca * nvira:].reshape(noccb, nvirb) v1a[i] += numpy.einsum('ia,ia->ia', e_ia_a, za) v1b[i] += numpy.einsum('ia,ia->ia', e_ia_b, zb) hx = numpy.hstack((v1a.reshape(nz, -1), v1b.reshape(nz, -1))) if wfnsym is not None and mol.symmetry: hx[:, sym_forbid] = 0 return hx return vind, hdiag
def get_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 sym_forbida = (orbsyma[occidxa, None] ^ orbsyma[viridxa]) != wfnsym sym_forbidb = (orbsymb[occidxb, None] ^ orbsymb[viridxb]) != wfnsym sym_forbid = numpy.hstack( (sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T e_ia = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel()**2 vresp = mf.gen_response(mo_coeff, mo_occ, hermi=1) def vind(zs): nz = len(zs) zs = numpy.asarray(zs).reshape(nz, -1) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 dmsa = (zs[:, :nocca * nvira] * d_ia[:nocca * nvira]).reshape( nz, nocca, nvira) dmsb = (zs[:, nocca * nvira:] * d_ia[nocca * nvira:]).reshape( nz, noccb, nvirb) dmsa = lib.einsum('xov,po,qv->xpq', dmsa, orboa, orbva.conj()) dmsb = lib.einsum('xov,po,qv->xpq', dmsb, orbob, orbvb.conj()) dmsa = dmsa + dmsa.conj().transpose(0, 2, 1) dmsb = dmsb + dmsb.conj().transpose(0, 2, 1) v1ao = vresp(numpy.asarray((dmsa, dmsb))) v1a = lib.einsum('xpq,po,qv->xov', v1ao[0], orboa.conj(), orbva) v1b = lib.einsum('xpq,po,qv->xov', v1ao[1], orbob.conj(), orbvb) hx = numpy.hstack((v1a.reshape(nz, -1), v1b.reshape(nz, -1))) hx += ed_ia * zs hx *= d_ia return hx return vind, hdiag
def caslst_by_irrep(casscf, mo_coeff, cas_irrep_nocc, cas_irrep_ncore=None, s=None, base=1): '''Given number of active orbitals for each irrep, return the orbital indices of active space Args: casscf : an :class:`CASSCF` or :class:`CASCI` object cas_irrep_nocc : list or dict Number of active orbitals for each irrep. It can be a dict, eg {'A1': 2, 'B2': 4} to indicate the active space size based on irrep names, or {0: 2, 3: 4} for irrep Id, or a list [2, 0, 0, 4] (identical to {0: 2, 3: 4}) in which the list index is served as the irrep Id. Kwargs: cas_irrep_ncore : list or dict Number of closed shells for each irrep. It can be a dict, eg {'A1': 6, 'B2': 4} to indicate the closed shells based on irrep names, or {0: 6, 3: 4} for irrep Id, or a list [6, 0, 0, 4] (identical to {0: 6, 3: 4}) in which the list index is served as the irrep Id. If cas_irrep_ncore is not given, the program will generate a guess based on the lowest :attr:`CASCI.ncore` orbitals. s : ndarray overlap matrix base : int 0-based (C-like) or 1-based (Fortran-like) caslst Returns: A list of orbital indices Examples: >>> from pyscf import gto, scf, mcscf >>> mol = gto.M(atom='N 0 0 0; N 0 0 1', basis='ccpvtz', symmetry=True, verbose=0) >>> mf = scf.RHF(mol) >>> mf.kernel() >>> mc = mcscf.CASSCF(mf, 12, 4) >>> mcscf.caslst_by_irrep(mc, mf.mo_coeff, {'E1gx':4, 'E1gy':4, 'E1ux':2, 'E1uy':2}) [5, 7, 8, 10, 11, 14, 15, 20, 25, 26, 31, 32] ''' mol = casscf.mol log = logger.Logger(casscf.stdout, casscf.verbose) if s is None: s = casscf._scf.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s) orbsym = numpy.asarray(orbsym) ncore = casscf.ncore irreps = set(orbsym) if cas_irrep_ncore is not None: irrep_ncore = {} for k, v in cas_irrep_ncore.items(): if isinstance(k, str): irrep_ncore[symm.irrep_name2id(mol.groupname, k)] = v else: irrep_ncore[k] = v ncore_rest = casscf.ncore - sum(irrep_ncore.values()) if ncore_rest > 0: # guess core configuration mask = numpy.ones(len(orbsym), dtype=bool) for ir in irrep_ncore: mask[orbsym == ir] = False core_rest = orbsym[mask][:ncore_rest] core_rest = dict([(ir, numpy.count_nonzero(core_rest==ir)) for ir in set(core_rest)]) log.info('Given core space %s < casscf core size %d', cas_irrep_ncore, casscf.ncore) log.info('Add %s to core configuration', core_rest) irrep_ncore.update(core_rest) elif ncore_rest < 0: raise ValueError('Given core space %s > casscf core size %d' % (cas_irrep_ncore, casscf.ncore)) else: irrep_ncore = dict([(ir, sum(orbsym[:ncore]==ir)) for ir in irreps]) if not isinstance(cas_irrep_nocc, dict): # list => dict cas_irrep_nocc = dict([(ir, n) for ir,n in enumerate(cas_irrep_nocc) if n > 0]) irrep_ncas = {} for k, v in cas_irrep_nocc.items(): if isinstance(k, str): irrep_ncas[symm.irrep_name2id(mol.groupname, k)] = v else: irrep_ncas[k] = v ncas_rest = casscf.ncas - sum(irrep_ncas.values()) if ncas_rest > 0: mask = numpy.ones(len(orbsym), dtype=bool) # remove core and specified active space for ir in irrep_ncas: mask[orbsym == ir] = False for ir, ncore in irrep_ncore.items(): idx = numpy.where(orbsym == ir)[0] mask[idx[:ncore]] = False cas_rest = orbsym[mask][:ncas_rest] cas_rest = dict([(ir, numpy.count_nonzero(cas_rest==ir)) for ir in set(cas_rest)]) log.info('Given active space %s < casscf active space size %d', cas_irrep_nocc, casscf.ncas) log.info('Add %s to active space', cas_rest) irrep_ncas.update(cas_rest) elif ncas_rest < 0: raise ValueError('Given active space %s > casscf active space size %d' % (cas_irrep_nocc, casscf.ncas)) caslst = [] for ir, ncas in irrep_ncas.items(): if ncas > 0: if ir in irrep_ncore: nc = irrep_ncore[ir] else: nc = 0 no = nc + ncas idx = numpy.where(orbsym == ir)[0] caslst.extend(idx[nc:no]) caslst = numpy.sort(numpy.asarray(caslst)) + base if len(caslst) < casscf.ncas: raise ValueError('Not enough orbitals found for core %s, cas %s' % (cas_irrep_ncore, cas_irrep_nocc)) if log.verbose >= logger.INFO: log.info('ncore for each irreps %s', dict([(symm.irrep_id2name(mol.groupname, k), v) for k,v in irrep_ncore.items()])) log.info('ncas for each irreps %s', dict([(symm.irrep_id2name(mol.groupname, k), v) for k,v in irrep_ncas.items()])) log.info('(%d-based) caslst = %s', base, caslst) return caslst
def get_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma = orbsyma % 10 orbsymb = orbsymb % 10 sym_forbida = (orbsyma[occidxa, None] ^ orbsyma[viridxa]) != wfnsym sym_forbidb = (orbsymb[occidxb, None] ^ orbsymb[viridxb]) != wfnsym sym_forbid = numpy.hstack( (sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = (mo_energy[0][viridxa, None] - mo_energy[0][occidxa]).T e_ia_b = (mo_energy[1][viridxb, None] - mo_energy[1][occidxb]).T e_ia = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel()**2 vresp = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 dmov = numpy.empty((2, nz, nao, nao)) for i in range(nz): z = d_ia * zs[i] za = z[:nocca * nvira].reshape(nocca, nvira) zb = z[nocca * nvira:].reshape(noccb, nvirb) dm = reduce(numpy.dot, (orboa, za, orbva.T)) dmov[0, i] = dm + dm.T dm = reduce(numpy.dot, (orbob, zb, orbvb.T)) dmov[1, i] = dm + dm.T v1ao = vresp(dmov) v1a = _ao2mo.nr_e2(v1ao[0], mo_coeff[0], (0, nocca, nocca, nmo)) v1b = _ao2mo.nr_e2(v1ao[1], mo_coeff[1], (0, noccb, noccb, nmo)) hx = numpy.hstack((v1a.reshape(nz, -1), v1b.reshape(nz, -1))) for i, z in enumerate(zs): hx[i] += ed_ia * z hx[i] *= d_ia return hx return vind, hdiag
def cylindrical_init_guess(mol, norb, nelec, orbsym, wfnsym=0, singlet=True, nroots=1): ''' FCI initial guess for system of cylindrical symmetry. (In testing) Examples: >>> mol = gto.M(atom='O; O 1 1.2', spin=2, symmetry=True) >>> orbsym = [6,7,2,3] >>> ci0 = fci.addons.cylindrical_init_guess(mol, 4, (3,3), orbsym, wfnsym=10)[0] >>> print(ci0.reshape(4,4)) >>> ci0 = fci.addons.cylindrical_init_guess(mol, 4, (3,3), orbsym, wfnsym=10, singlet=False)[0] >>> print(ci0.reshape(4,4)) ''' neleca, nelecb = _unpack_nelec(nelec) if isinstance(orbsym[0], str): orbsym = [symm.irrep_name2id(mol.groupname, x) for x in orbsym] orbsym = numpy.asarray(orbsym) if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) if mol.groupname in ('Dooh', 'Coov'): def irrep_id2lz(irrep_id): # See also symm.basis.DOOH_IRREP_ID_TABLE level = irrep_id // 10 d2h_id = irrep_id % 10 # irrep_id 0,1,4,5 corresponds to lz = 0,2,4,... # irrep_id 2,3,6,7 corresponds to lz = 1,3,5,... lz = level * 2 + ((d2h_id == 2) | (d2h_id == 3) | (d2h_id == 6) | (d2h_id == 7)) if isinstance(irrep_id, (int, numpy.number)): # irrep_id 1,3,4,6 corresponds to E_y (E_{(-)}) # irrep_id 0,2,5,7 corresponds to E_x (E_{(+)}) if (d2h_id == 1) | (d2h_id == 3) | (d2h_id == 4) | (d2h_id == 6): lz = -lz else: lz[(d2h_id == 1) | (d2h_id == 3) | (d2h_id == 4) | (d2h_id == 6)] *= -1 return lz orb_lz = irrep_id2lz(orbsym) wfn_lz = irrep_id2lz(wfnsym) d2h_wfnsym_id = wfnsym % 10 else: raise NotImplementedError orb_lz = wfn_lz = d2h_wfnsym_id = None occslsta = occslstb = cistring._gen_occslst(range(norb), neleca) if neleca != nelecb: occslstb = cistring._gen_occslst(range(norb), nelecb) na = len(occslsta) nb = len(occslsta) gx_mask = orbsym == 2 gy_mask = orbsym == 3 ux_mask = orbsym == 7 uy_mask = orbsym == 6 all_lz = set(abs(orb_lz)) def search_open_shell_det(occ_lst): occ_mask = numpy.zeros(norb, dtype=bool) occ_mask[occ_lst] = True # First search Lz of the open-shell orbital for lz_open in all_lz: if numpy.count_nonzero(orb_lz == lz_open) % 2 == 1: break n_gx = numpy.count_nonzero(gx_mask & occ_mask & (orb_lz == lz_open)) n_gy = numpy.count_nonzero(gy_mask & occ_mask & (orb_lz == -lz_open)) n_ux = numpy.count_nonzero(ux_mask & occ_mask & (orb_lz == lz_open)) n_uy = numpy.count_nonzero(uy_mask & occ_mask & (orb_lz == -lz_open)) if n_gx > n_gy: idx = numpy.where(occ_mask & (orb_lz == lz_open) & gx_mask)[0][0] idy = numpy.where((~occ_mask) & (orb_lz == -lz_open) & gy_mask)[0][0] elif n_gx < n_gy: idx = numpy.where((~occ_mask) & (orb_lz == lz_open) & gx_mask)[0][0] idy = numpy.where(occ_mask & (orb_lz == -lz_open) & gy_mask)[0][0] elif n_ux > n_uy: idx = numpy.where(occ_mask & (orb_lz == lz_open) & ux_mask)[0][0] idy = numpy.where((~occ_mask) & (orb_lz == -lz_open) & uy_mask)[0][0] elif n_ux < n_uy: idx = numpy.where((~occ_mask) & (orb_lz == lz_open) & ux_mask)[0][0] idy = numpy.where(occ_mask & (orb_lz == -lz_open) & uy_mask)[0][0] else: raise RuntimeError nelec = len(occ_lst) det_x = occ_mask.copy() det_x[idx] = True det_x[idy] = False str_x = ''.join(['1' if i else '0' for i in det_x[::-1]]) addr_x = cistring.str2addr(norb, nelec, str_x) det_y = occ_mask.copy() det_y[idx] = False det_y[idy] = True str_y = ''.join(['1' if i else '0' for i in det_y[::-1]]) addr_y = cistring.str2addr(norb, nelec, str_y) return addr_x, addr_y ci0 = [] iroot = 0 for addr in range(na * nb): ci_1 = numpy.zeros((na, nb)) addra = addr // nb addrb = addr % nb occa = occslsta[addra] occb = occslstb[addrb] tot_sym = 0 for i in occa: tot_sym ^= orbsym[i] for i in occb: tot_sym ^= orbsym[i] if tot_sym == d2h_wfnsym_id: n_Ex_a = (gx_mask[occa]).sum() + (ux_mask[occa]).sum() n_Ey_a = (gy_mask[occa]).sum() + (uy_mask[occa]).sum() n_Ex_b = (gx_mask[occb]).sum() + (ux_mask[occb]).sum() n_Ey_b = (gy_mask[occb]).sum() + (uy_mask[occb]).sum() if abs(n_Ex_a - n_Ey_a) == 1 and abs(n_Ex_b - n_Ey_b) == 1: # open-shell for both alpha det and beta det e.g. the # valence part of O2 molecule addr_x_a, addr_y_a = search_open_shell_det(occa) addr_x_b, addr_y_b = search_open_shell_det(occb) if singlet: if wfn_lz == 0: ci_1[addr_x_a,addr_x_b] = \ ci_1[addr_y_a,addr_y_b] = numpy.sqrt(.5) else: ci_1[addr_x_a, addr_x_b] = numpy.sqrt(.5) ci_1[addr_y_a, addr_y_b] = -numpy.sqrt(.5) else: ci_1[addr_x_a, addr_y_b] = numpy.sqrt(.5) ci_1[addr_y_a, addr_x_b] = -numpy.sqrt(.5) else: # TODO: Other direct-product to direct-sum transofromation # which involves CG coefficients. ci_1[addra, addrb] = 1 ci0.append(ci_1.ravel()) iroot += 1 if iroot >= nroots: break return ci0
def gen_tda_operation(mf, fock_ao=None, wfnsym=None): '''(A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma_in_d2h = numpy.asarray(orbsyma) % 10 orbsymb_in_d2h = numpy.asarray(orbsymb) % 10 sym_forbida = (orbsyma_in_d2h[occidxa, None] ^ orbsyma_in_d2h[viridxa]) != wfnsym sym_forbidb = (orbsymb_in_d2h[occidxb, None] ^ orbsymb_in_d2h[viridxb]) != wfnsym sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = mo_energy[0][viridxa] - mo_energy[0][occidxa, None] e_ia_b = mo_energy[1][viridxb] - mo_energy[1][occidxb, None] e_ia = numpy.hstack((e_ia_a.reshape(-1), e_ia_b.reshape(-1))) hdiag = e_ia if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) vresp = mf.gen_response(hermi=0, max_memory=max_memory) def vind(zs): zs = numpy.asarray(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 za = zs[:, :nocca * nvira].reshape(-1, nocca, nvira) zb = zs[:, nocca * nvira:].reshape(-1, noccb, nvirb) dmova = lib.einsum('xov,po,qv->xpq', za, orboa, orbva.conj()) dmovb = lib.einsum('xov,po,qv->xpq', zb, orbob, orbvb.conj()) v1ao = vresp(numpy.asarray((dmova, dmovb))) v1a = lib.einsum('xpq,po,qv->xov', v1ao[0], orboa.conj(), orbva) v1b = lib.einsum('xpq,po,qv->xov', v1ao[1], orbob.conj(), orbvb) v1a += numpy.einsum('xia,ia->xia', za, e_ia_a) v1b += numpy.einsum('xia,ia->xia', zb, e_ia_b) nz = zs.shape[0] hx = numpy.hstack((v1a.reshape(nz, -1), v1b.reshape(nz, -1))) if wfnsym is not None and mol.symmetry: hx[:, sym_forbid] = 0 return hx return vind, hdiag
def cylindrical_init_guess(mol, norb, nelec, orbsym, wfnsym=0, singlet=True, nroots=1): ''' FCI initial guess for system of cylindrical symmetry. (In testing) Examples: >>> mol = gto.M(atom='O; O 1 1.2', spin=2, symmetry=True) >>> orbsym = [6,7,2,3] >>> ci0 = fci.addons.cylindrical_init_guess(mol, 4, (3,3), orbsym, wfnsym=10)[0] >>> print(ci0.reshape(4,4)) >>> ci0 = fci.addons.cylindrical_init_guess(mol, 4, (3,3), orbsym, wfnsym=10, singlet=False)[0] >>> print(ci0.reshape(4,4)) ''' neleca, nelecb = _unpack_nelec(nelec) if isinstance(orbsym[0], str): orbsym = [symm.irrep_name2id(mol.groupname, x) for x in orbsym] orbsym = numpy.asarray(orbsym) if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) if mol.groupname in ('Dooh', 'Coov'): def irrep_id2lz(irrep_id): # See also symm.basis.DOOH_IRREP_ID_TABLE level = irrep_id // 10 d2h_id = irrep_id % 10 # irrep_id 0,1,4,5 corresponds to lz = 0,2,4,... # irrep_id 2,3,6,7 corresponds to lz = 1,3,5,... lz = level * 2 + ((d2h_id==2) | (d2h_id==3) | (d2h_id==6) | (d2h_id==7)) if isinstance(irrep_id, (int, numpy.number)): # irrep_id 1,3,4,6 corresponds to E_y (E_{(-)}) # irrep_id 0,2,5,7 corresponds to E_x (E_{(+)}) if (d2h_id==1) | (d2h_id==3) | (d2h_id==4) | (d2h_id==6): lz = -lz else: lz[(d2h_id==1) | (d2h_id==3) | (d2h_id==4) | (d2h_id==6)] *= -1 return lz orb_lz = irrep_id2lz(orbsym) wfn_lz = irrep_id2lz(wfnsym) d2h_wfnsym_id = wfnsym % 10 else: raise NotImplementedError orb_lz = wfn_lz = d2h_wfnsym_id = None occslsta = occslstb = cistring._gen_occslst(range(norb), neleca) if neleca != nelecb: occslstb = cistring._gen_occslst(range(norb), nelecb) na = len(occslsta) nb = len(occslsta) gx_mask = orbsym == 2 gy_mask = orbsym == 3 ux_mask = orbsym == 7 uy_mask = orbsym == 6 all_lz = set(abs(orb_lz)) def search_open_shell_det(occ_lst): occ_mask = numpy.zeros(norb, dtype=bool) occ_mask[occ_lst] = True # First search Lz of the open-shell orbital for lz_open in all_lz: if numpy.count_nonzero(orb_lz == lz_open) % 2 == 1: break n_gx = numpy.count_nonzero(gx_mask & occ_mask & (orb_lz == lz_open)) n_gy = numpy.count_nonzero(gy_mask & occ_mask & (orb_lz ==-lz_open)) n_ux = numpy.count_nonzero(ux_mask & occ_mask & (orb_lz == lz_open)) n_uy = numpy.count_nonzero(uy_mask & occ_mask & (orb_lz ==-lz_open)) if n_gx > n_gy: idx = numpy.where(occ_mask & (orb_lz == lz_open) & gx_mask)[0][0] idy = numpy.where((~occ_mask) & (orb_lz ==-lz_open) & gy_mask)[0][0] elif n_gx < n_gy: idx = numpy.where((~occ_mask) & (orb_lz == lz_open) & gx_mask)[0][0] idy = numpy.where(occ_mask & (orb_lz ==-lz_open) & gy_mask)[0][0] elif n_ux > n_uy: idx = numpy.where(occ_mask & (orb_lz == lz_open) & ux_mask)[0][0] idy = numpy.where((~occ_mask) & (orb_lz ==-lz_open) & uy_mask)[0][0] elif n_ux < n_uy: idx = numpy.where((~occ_mask) & (orb_lz == lz_open) & ux_mask)[0][0] idy = numpy.where(occ_mask & (orb_lz ==-lz_open) & uy_mask)[0][0] else: raise RuntimeError nelec = len(occ_lst) det_x = occ_mask.copy() det_x[idx] = True det_x[idy] = False str_x = ''.join(['1' if i else '0' for i in det_x[::-1]]) addr_x = cistring.str2addr(norb, nelec, str_x) det_y = occ_mask.copy() det_y[idx] = False det_y[idy] = True str_y = ''.join(['1' if i else '0' for i in det_y[::-1]]) addr_y = cistring.str2addr(norb, nelec, str_y) return addr_x, addr_y ci0 = [] iroot = 0 for addr in range(na*nb): ci_1 = numpy.zeros((na,nb)) addra = addr // nb addrb = addr % nb occa = occslsta[addra] occb = occslstb[addrb] tot_sym = 0 for i in occa: tot_sym ^= orbsym[i] for i in occb: tot_sym ^= orbsym[i] if tot_sym == d2h_wfnsym_id: n_Ex_a = (gx_mask[occa]).sum() + (ux_mask[occa]).sum() n_Ey_a = (gy_mask[occa]).sum() + (uy_mask[occa]).sum() n_Ex_b = (gx_mask[occb]).sum() + (ux_mask[occb]).sum() n_Ey_b = (gy_mask[occb]).sum() + (uy_mask[occb]).sum() if abs(n_Ex_a - n_Ey_a) == 1 and abs(n_Ex_b - n_Ey_b) == 1: # open-shell for both alpha det and beta det e.g. the # valence part of O2 molecule addr_x_a, addr_y_a = search_open_shell_det(occa) addr_x_b, addr_y_b = search_open_shell_det(occb) if singlet: if wfn_lz == 0: ci_1[addr_x_a,addr_x_b] = \ ci_1[addr_y_a,addr_y_b] = numpy.sqrt(.5) else: ci_1[addr_x_a,addr_x_b] = numpy.sqrt(.5) ci_1[addr_y_a,addr_y_b] =-numpy.sqrt(.5) else: ci_1[addr_x_a,addr_y_b] = numpy.sqrt(.5) ci_1[addr_y_a,addr_x_b] =-numpy.sqrt(.5) else: # TODO: Other direct-product to direct-sum transofromation # which involves CG coefficients. ci_1[addra,addrb] = 1 ci0.append(ci_1.ravel()) iroot += 1 if iroot >= nroots: break return ci0
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff[0].dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff[0].shape occidxa = numpy.where(mo_occ[0] > 0)[0] occidxb = numpy.where(mo_occ[1] > 0)[0] viridxa = numpy.where(mo_occ[0] == 0)[0] viridxb = numpy.where(mo_occ[1] == 0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsyma_in_d2h = numpy.asarray(orbsyma) % 10 orbsymb_in_d2h = numpy.asarray(orbsymb) % 10 sym_forbida = (orbsyma_in_d2h[occidxa, None] ^ orbsyma_in_d2h[viridxa]) != wfnsym sym_forbidb = (orbsymb_in_d2h[occidxb, None] ^ orbsymb_in_d2h[viridxb]) != wfnsym sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel())) e_ia_a = mo_energy[0][viridxa] - mo_energy[0][occidxa, None] e_ia_b = mo_energy[1][viridxb] - mo_energy[1][occidxb, None] e_ia = hdiag = numpy.hstack((e_ia_a.ravel(), e_ia_b.ravel())) if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag, -hdiag)) mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) vresp = mf.gen_response(hermi=0, max_memory=max_memory) def vind(xys): nz = len(xys) xys = numpy.asarray(xys).reshape(nz, 2, -1) if wfnsym is not None and mol.symmetry: # shape(nz,2,-1): 2 ~ X,Y xys = numpy.copy(xys) xys[:, :, sym_forbid] = 0 xs, ys = xys.transpose(1, 0, 2) xa = xs[:, :nocca * nvira].reshape(nz, nocca, nvira) xb = xs[:, nocca * nvira:].reshape(nz, noccb, nvirb) ya = ys[:, :nocca * nvira].reshape(nz, nocca, nvira) yb = ys[:, nocca * nvira:].reshape(nz, noccb, nvirb) # dms = AX + BY dmsa = lib.einsum('xov,po,qv->xpq', xa, orboa, orbva.conj()) dmsa += lib.einsum('xov,pv,qo->xpq', ya, orbva, orboa.conj()) dmsb = lib.einsum('xov,po,qv->xpq', xb, orbob, orbvb.conj()) dmsb += lib.einsum('xov,pv,qo->xpq', yb, orbvb, orbob.conj()) v1ao = vresp(numpy.asarray((dmsa, dmsb))) v1aov = lib.einsum('xpq,po,qv->xov', v1ao[0], orboa.conj(), orbva) v1bov = lib.einsum('xpq,po,qv->xov', v1ao[1], orbob.conj(), orbvb) v1avo = lib.einsum('xpq,pv,qo->xov', v1ao[0], orbva.conj(), orboa) v1bvo = lib.einsum('xpq,pv,qo->xov', v1ao[1], orbvb.conj(), orbob) v1ov = xs * e_ia # AX v1vo = ys * e_ia # AY v1ov[:, :nocca * nvira] += v1aov.reshape(nz, -1) v1vo[:, :nocca * nvira] += v1avo.reshape(nz, -1) v1ov[:, nocca * nvira:] += v1bov.reshape(nz, -1) v1vo[:, nocca * nvira:] += v1bvo.reshape(nz, -1) if wfnsym is not None and mol.symmetry: v1ov[:, sym_forbid] = 0 v1vo[:, sym_forbid] = 0 hx = numpy.hstack((v1ov, -v1vo)) return hx return vind, hdiag
def caslst_by_irrep(casscf, mo_coeff, cas_irrep_nocc, cas_irrep_ncore=None, s=None, base=BASE): '''Given number of active orbitals for each irrep, return the orbital indices of active space Args: casscf : an :class:`CASSCF` or :class:`CASCI` object cas_irrep_nocc : list or dict Number of active orbitals for each irrep. It can be a dict, eg {'A1': 2, 'B2': 4} to indicate the active space size based on irrep names, or {0: 2, 3: 4} for irrep Id, or a list [2, 0, 0, 4] (identical to {0: 2, 3: 4}) in which the list index is served as the irrep Id. Kwargs: cas_irrep_ncore : list or dict Number of closed shells for each irrep. It can be a dict, eg {'A1': 6, 'B2': 4} to indicate the closed shells based on irrep names, or {0: 6, 3: 4} for irrep Id, or a list [6, 0, 0, 4] (identical to {0: 6, 3: 4}) in which the list index is served as the irrep Id. If cas_irrep_ncore is not given, the program will generate a guess based on the lowest :attr:`CASCI.ncore` orbitals. s : ndarray overlap matrix base : int 0-based (C-like) or 1-based (Fortran-like) caslst Returns: A list of orbital indices Examples: >>> from pyscf import gto, scf, mcscf >>> mol = gto.M(atom='N 0 0 0; N 0 0 1', basis='ccpvtz', symmetry=True, verbose=0) >>> mf = scf.RHF(mol) >>> mf.kernel() >>> mc = mcscf.CASSCF(mf, 12, 4) >>> mcscf.caslst_by_irrep(mc, mf.mo_coeff, {'E1gx':4, 'E1gy':4, 'E1ux':2, 'E1uy':2}) [5, 7, 8, 10, 11, 14, 15, 20, 25, 26, 31, 32] ''' mol = casscf.mol log = logger.Logger(casscf.stdout, casscf.verbose) orbsym = numpy.asarray(scf.hf_symm.get_orbsym(mol, mo_coeff)) ncore = casscf.ncore irreps = set(orbsym) if cas_irrep_ncore is not None: irrep_ncore = {} for k, v in cas_irrep_ncore.items(): if isinstance(k, str): irrep_ncore[symm.irrep_name2id(mol.groupname, k)] = v else: irrep_ncore[k] = v ncore_rest = ncore - sum(irrep_ncore.values()) if ncore_rest > 0: # guess core configuration mask = numpy.ones(len(orbsym), dtype=bool) for ir in irrep_ncore: mask[orbsym == ir] = False core_rest = orbsym[mask][:ncore_rest] core_rest = dict([(ir, numpy.count_nonzero(core_rest == ir)) for ir in set(core_rest)]) log.info('Given core space %s < casscf core size %d', cas_irrep_ncore, ncore) log.info('Add %s to core configuration', core_rest) irrep_ncore.update(core_rest) elif ncore_rest < 0: raise ValueError('Given core space %s > casscf core size %d' % (cas_irrep_ncore, ncore)) else: irrep_ncore = dict([(ir, sum(orbsym[:ncore] == ir)) for ir in irreps]) if not isinstance(cas_irrep_nocc, dict): # list => dict cas_irrep_nocc = dict([(ir, n) for ir, n in enumerate(cas_irrep_nocc) if n > 0]) irrep_ncas = {} for k, v in cas_irrep_nocc.items(): if isinstance(k, str): irrep_ncas[symm.irrep_name2id(mol.groupname, k)] = v else: irrep_ncas[k] = v ncas_rest = casscf.ncas - sum(irrep_ncas.values()) if ncas_rest > 0: mask = numpy.ones(len(orbsym), dtype=bool) # remove core and specified active space for ir in irrep_ncas: mask[orbsym == ir] = False for ir, ncore in irrep_ncore.items(): idx = numpy.where(orbsym == ir)[0] mask[idx[:ncore]] = False cas_rest = orbsym[mask][:ncas_rest] cas_rest = dict([(ir, numpy.count_nonzero(cas_rest == ir)) for ir in set(cas_rest)]) log.info('Given active space %s < casscf active space size %d', cas_irrep_nocc, casscf.ncas) log.info('Add %s to active space', cas_rest) irrep_ncas.update(cas_rest) elif ncas_rest < 0: raise ValueError( 'Given active space %s > casscf active space size %d' % (cas_irrep_nocc, casscf.ncas)) caslst = [] for ir, ncas in irrep_ncas.items(): if ncas > 0: if ir in irrep_ncore: nc = irrep_ncore[ir] else: nc = 0 no = nc + ncas idx = numpy.where(orbsym == ir)[0] caslst.extend(idx[nc:no]) caslst = numpy.sort(numpy.asarray(caslst)) + base if len(caslst) < casscf.ncas: raise ValueError('Not enough orbitals found for core %s, cas %s' % (cas_irrep_ncore, cas_irrep_nocc)) if log.verbose >= logger.INFO: log.info( 'ncore for each irreps %s', dict([(symm.irrep_id2name(mol.groupname, k), v) for k, v in irrep_ncore.items()])) log.info( 'ncas for each irreps %s', dict([(symm.irrep_id2name(mol.groupname, k), v) for k, v in irrep_ncas.items()])) log.info('(%d-based) caslst = %s', base, caslst) return caslst
def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute (A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps sym_forbid = (orbsym_in_d2h[occidx, None] ^ orbsym_in_d2h[viridx]) != wfnsym if fock_ao is None: #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) else: fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) foo = fock[occidx[:, None], occidx] fvv = fock[viridx[:, None], viridx] hdiag = fvv.diagonal() - foo.diagonal()[:, None] if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() mo_coeff = numpy.asarray(numpy.hstack((orbo, orbv)), order='F') vresp = mf.gen_response(singlet=singlet, hermi=0) def vind(zs): zs = numpy.asarray(zs).reshape(-1, nocc, nvir) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs) zs[:, sym_forbid] = 0 # *2 for double occupancy dmov = lib.einsum('xov,po,qv->xpq', zs * 2, orbo, orbv.conj()) v1ao = vresp(dmov) v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo.conj(), orbv) v1ov += lib.einsum('xqs,sp->xqp', zs, fvv) v1ov -= lib.einsum('xpr,sp->xsr', zs, foo) if wfnsym is not None and mol.symmetry: v1ov[:, sym_forbid] = 0 return v1ov.reshape(v1ov.shape[0], -1) return vind, hdiag
def select_mo_by_irrep(casscf, cas_occ_num, mo = None, base=1): if mo is None: mo = casscf.mo_coeff orbsym = pyscf.symm.label_orb_symm(casscf.mol, casscf.mol.irrep_id, casscf.mol.symm_orb, mo, s=casscf._scf.get_ovlp()) orbsym = orbsym[casscf.ncore:] caslst = [] for k, v in cas_occ_num.iteritems(): orb_irrep = [ casscf.ncore + base + i for i in range(len(orbsym)) if orbsym[i]== symm.irrep_name2id(casscf.mol.groupname,k) ] caslst.extend(orb_irrep[:v]) return caslst
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps sym_forbid = (orbsym_in_d2h[occidx, None] ^ orbsym_in_d2h[viridx]) != wfnsym #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) #fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) #foo = fock[occidx[:,None],occidx] #fvv = fock[viridx[:,None],viridx] foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) hdiag = fvv.diagonal() - foo.diagonal()[:, None] if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag.ravel(), -hdiag.ravel())) mo_coeff = numpy.asarray(numpy.hstack((orbo, orbv)), order='F') vresp = mf.gen_response(singlet=singlet, hermi=0) def vind(xys): xys = numpy.asarray(xys).reshape(-1, 2, nocc, nvir) if wfnsym is not None and mol.symmetry: # shape(nz,2,nocc,nvir): 2 ~ X,Y xys = numpy.copy(xys) xys[:, :, sym_forbid] = 0 xs, ys = xys.transpose(1, 0, 2, 3) # dms = AX + BY # *2 for double occupancy dms = lib.einsum('xov,po,qv->xpq', xs * 2, orbo, orbv.conj()) dms += lib.einsum('xov,pv,qo->xpq', ys * 2, orbv, orbo.conj()) v1ao = vresp(dms) v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo.conj(), orbv) v1vo = lib.einsum('xpq,pv,qo->xov', v1ao, orbv.conj(), orbo) v1ov += lib.einsum('xqs,sp->xqp', xs, fvv) # AX v1ov -= lib.einsum('xpr,sp->xsr', xs, foo) # AX v1vo += lib.einsum('xqs,sp->xqp', ys, fvv) # AY v1vo -= lib.einsum('xpr,sp->xsr', ys, foo) # AY if wfnsym is not None and mol.symmetry: v1ov[:, sym_forbid] = 0 v1vo[:, sym_forbid] = 0 # (AX, -AY) nz = xys.shape[0] hx = numpy.hstack((v1ov.reshape(nz, -1), -v1vo.reshape(nz, -1))) return hx return vind, hdiag
def sort_mo_by_irrep(casscf, mo_coeff, cas_irrep_nocc, cas_irrep_ncore=None, s=None): '''Given number of active orbitals for each irrep, form the active space wrt the indices of MOs Args: casscf : an :class:`CASSCF` or :class:`CASCI` object cas_irrep_nocc : list or dict Number of active orbitals for each irrep. It can be a dict, eg {'A1': 2, 'B2': 4} to indicate the active space size based on irrep names, or {0: 2, 3: 4} for irrep Id, or a list [2, 0, 0, 4] (identical to {0: 2, 3: 4}) in which the list index is served as the irrep Id. Kwargs: cas_irrep_ncore : list or dict Number of closed shells for each irrep. It can be a dict, eg {'A1': 6, 'B2': 4} to indicate the closed shells based on irrep names, or {0: 6, 3: 4} for irrep Id, or a list [6, 0, 0, 4] (identical to {0: 6, 3: 4}) in which the list index is served as the irrep Id. If cas_irrep_ncore is not given, the program will generate a guess based on the lowest :attr:`CASCI.ncore` orbitals. s : ndarray overlap matrix Returns: sorted orbitals, ordered as [c,..,c,a,..,a,v,..,v] Examples: >>> from pyscf import gto, scf, mcscf >>> mol = gto.M(atom='N 0 0 0; N 0 0 1', basis='ccpvtz', verbose=0) >>> mf = scf.RHF(mol) >>> mf.kernel() >>> mc = mcscf.CASSCF(mf, 12, 4) >>> mo = mcscf.sort_mo_by_irrep(mc, mf.mo_coeff, {'E1gx':4, 'E1gy':4, 'E1ux':2, 'E1uy':2}) >>> mc.kernel(mo)[0] -109.058040031 ''' if s is None: s = casscf._scf.get_ovlp() orbsym = pyscf.symm.label_orb_symm(casscf.mol, casscf.mol.irrep_id, casscf.mol.symm_orb, mo_coeff, s) if cas_irrep_ncore is None: ncore = casscf.ncore nocc = ncore + casscf.ncas cas_irrep_ncore = {} for x in orbsym[:ncore]: if x in cas_irrep_ncore: cas_irrep_ncore[x] += 1 else: cas_irrep_ncore[x] = 0 orbidx_by_irrep = {} for i,x in enumerate(orbsym): if x in orbidx_by_irrep: orbidx_by_irrep[x].append(i) else: orbidx_by_irrep[x] = [i] # list => dict if not isinstance(cas_irrep_nocc, dict): cas_irrep_nocc = dict([(ir, n) for ir,n in enumerate(cas_irrep_nocc) if n > 0]) caslst = [] for k, ncas in cas_irrep_nocc.iteritems(): if isinstance(k, str): irid = symm.irrep_name2id(casscf.mol.groupname, k) else: irid = k idx = orbidx_by_irrep[irid] if irid in cas_irrep_ncore: ncore = cas_irrep_ncore[irid] else: ncore = 0 caslst.extend(idx[ncore:ncore+ncas]) return sort_mo(casscf, mo_coeff, sorted(caslst), 0)