def check_transformer_cache (self): assert (isinstance (self.smult, (int, np.number))) neleca, nelecb = _unpack_nelec (self.nelec) if self.transformer is None: self.transformer = CSFTransformer (self.norb, neleca, nelecb, self.smult) else: self.transformer._update_spin_cache (self.norb, neleca, nelecb, self.smult)
def hilbert_sector_weight(ci, norb, nelec, smult, is_hilbert=False): if np.asarray(nelec).size == 1: nelec = _unpack_nelec(nelec, spin=(smult - 1)) if not is_hilbert: ci = fock2hilbert(ci, norb, nelec) norm = CSFTransformer(norb, nelec[0], nelec[1], smult).vec_det2csf(ci, normalize=False, return_norm=True)[1] return norm**2
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 debug_lagrange(self, Lvec, bvec, Aop, Adiag, iroot=None, mo=None, ci=None, **kwargs): if iroot is None: iroot = self.iroot if mo is None: mo = self.base.mo_coeff if ci is None: ci = self.base.ci lib.logger.info( self, '{} gradient: iroot = {}'.format(self.base.__class__.__name__, iroot)) ngorb = self.ngorb nci = self.nci nroots = self.nroots ndet = nci // nroots ncore = self.base.ncore ncas = self.base.ncas nelecas = self.base.nelecas nocc = ncore + ncas nlag = self.nlag ci = np.asarray(self.base.ci).reshape(nroots, -1) err = Aop(Lvec) + bvec eorb = self.base.unpack_uniq_var(err[:ngorb]) eci = err[ngorb:].reshape(nroots, -1) borb = self.base.unpack_uniq_var(bvec[:ngorb]) bci = bvec[ngorb:].reshape(nroots, -1) Lorb = self.base.unpack_uniq_var(Lvec[:ngorb]) Lci = Lvec[ngorb:].reshape(nroots, ndet) Aci = Adiag[ngorb:].reshape(nroots, ndet) Lci_ci_ovlp = ( np.asarray(ci).reshape(nroots, -1).conjugate() @ Lci.T).T Lci_Lci_ovlp = (Lci.conjugate() @ Lci.T).T eci_ci_ovlp = ( np.asarray(ci).reshape(nroots, -1).conjugate() @ eci.T).T bci_ci_ovlp = ( np.asarray(ci).reshape(nroots, -1).conjugate() @ bci.T).T ci_ci_ovlp = ci.conjugate() @ ci.T lib.logger.debug( self, "{} gradient RHS, inactive-active orbital rotations:\n{}".format( self.base.__class__.__name__, borb[:ncore, ncore:nocc])) lib.logger.debug( self, "{} gradient RHS, inactive-external orbital rotations:\n{}".format( self.base.__class__.__name__, borb[:ncore, nocc:])) lib.logger.debug( self, "{} gradient RHS, active-external orbital rotations:\n{}".format( self.base.__class__.__name__, borb[ncore:nocc, nocc:])) lib.logger.debug( self, "{} gradient residual, inactive-active orbital rotations:\n{}". format(self.base.__class__.__name__, eorb[:ncore, ncore:nocc])) lib.logger.debug( self, "{} gradient residual, inactive-external orbital rotations:\n{}". format(self.base.__class__.__name__, eorb[:ncore, nocc:])) lib.logger.debug( self, "{} gradient residual, active-external orbital rotations:\n{}". format(self.base.__class__.__name__, eorb[ncore:nocc, nocc:])) lib.logger.debug( self, "{} gradient Lagrange factor, inactive-active orbital rotations:\n{}" .format(self.base.__class__.__name__, Lorb[:ncore, ncore:nocc])) lib.logger.debug( self, "{} gradient Lagrange factor, inactive-external orbital rotations:\n{}" .format(self.base.__class__.__name__, Lorb[:ncore, nocc:])) lib.logger.debug( self, "{} gradient Lagrange factor, active-external orbital rotations:\n{}" .format(self.base.__class__.__name__, Lorb[ncore:nocc, nocc:])) ''' lib.logger.debug (self, "{} gradient RHS, inactive-inactive orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, borb[:ncore,:ncore])) lib.logger.debug (self, "{} gradient RHS, active-active orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, borb[ncore:nocc,ncore:nocc])) lib.logger.debug (self, "{} gradient RHS, external-external orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, borb[nocc:,nocc:])) lib.logger.debug (self, "{} gradient Lagrange factor, inactive-inactive orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, Lorb[:ncore,:ncore])) lib.logger.debug (self, "{} gradient Lagrange factor, active-active orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, Lorb[ncore:nocc,ncore:nocc])) lib.logger.debug (self, "{} gradient Lagrange factor, external-external orbital rotations (redundant!):\n{}".format ( self.base.__class__.__name__, Lorb[nocc:,nocc:])) ''' lib.logger.debug( self, "{} gradient Lagrange factor, CI part overlap with true CI SA space:\n{}" .format(self.base.__class__.__name__, Lci_ci_ovlp)) lib.logger.debug( self, "{} gradient Lagrange factor, CI part self overlap matrix:\n{}". format(self.base.__class__.__name__, Lci_Lci_ovlp)) lib.logger.debug( self, "{} gradient Lagrange factor, CI vector self overlap matrix:\n{}". format(self.base.__class__.__name__, ci_ci_ovlp)) lib.logger.debug( self, "{} gradient Lagrange factor, CI part response overlap with SA space:\n{}" .format(self.base.__class__.__name__, bci_ci_ovlp)) lib.logger.debug( self, "{} gradient Lagrange factor, CI part residual overlap with SA space:\n{}" .format(self.base.__class__.__name__, eci_ci_ovlp)) neleca, nelecb = _unpack_nelec(nelecas) spin = neleca - nelecb + 1 csf = CSFTransformer(ncas, neleca, nelecb, spin) ecsf = csf.vec_det2csf(eci, normalize=False, order='C') err_norm_det = linalg.norm(err) err_norm_csf = linalg.norm(np.append(eorb, ecsf.ravel())) lib.logger.debug( self, "{} gradient: determinant residual = {}, CSF residual = {}".format( self.base.__class__.__name__, err_norm_det, err_norm_csf)) ci_lbls, ci_csf = csf.printable_largest_csf(ci, 10, isdet=True, normalize=True, order='C') bci_lbls, bci_csf = csf.printable_largest_csf(bci, 10, isdet=True, normalize=False, order='C') eci_lbls, eci_csf = csf.printable_largest_csf(eci, 10, isdet=True, normalize=False, order='C') Lci_lbls, Lci_csf = csf.printable_largest_csf(Lci, 10, isdet=True, normalize=False, order='C') Aci_lbls, Aci_csf = csf.printable_largest_csf(Aci, 10, isdet=True, normalize=False, order='C') ncsf = bci_csf.shape[1] for iroot in range(self.nroots): lib.logger.debug( self, "{} gradient Lagrange factor, CI part root {} spin square: {}". format(self.base.__class__.__name__, iroot, spin_square0(Lci[iroot], ncas, nelecas))) lib.logger.debug(self, "Base CI vector") for icsf in range(ncsf): lib.logger.debug( self, '{} {}'.format(ci_lbls[iroot, icsf], ci_csf[iroot, icsf])) lib.logger.debug(self, "CI gradient:") for icsf in range(ncsf): lib.logger.debug( self, '{} {}'.format(bci_lbls[iroot, icsf], bci_csf[iroot, icsf])) lib.logger.debug(self, "CI residual:") for icsf in range(ncsf): lib.logger.debug( self, '{} {}'.format(eci_lbls[iroot, icsf], eci_csf[iroot, icsf])) lib.logger.debug(self, "CI Lagrange vector:") for icsf in range(ncsf): lib.logger.debug( self, '{} {}'.format(Lci_lbls[iroot, icsf], Lci_csf[iroot, icsf])) lib.logger.debug(self, "Diagonal of Hessian matrix CI part:") for icsf in range(ncsf): lib.logger.debug( self, '{} {}'.format(Aci_lbls[iroot, icsf], Aci_csf[iroot, icsf])) '''
class FCISolver (direct_spin1.FCISolver): r''' get_init_guess uses csfstring.py and csdstring.py to construct a spin-symmetry-adapted initial guess, and the Davidson algorithm is carried out in the CSF basis. However, the ci attribute is put in the determinant basis at the end of it all, and "ci0" is also assumed to be in the determinant basis.''' pspace_size = getattr(__config__, 'fci_csf_FCI_pspace_size', 200) def __init__(self, mol=None, smult=None): self.smult = smult self.transformer = None self.mask_cache = [0, 0, 0, 0] super().__init__(mol) def get_init_guess(self, norb, nelec, nroots, hdiag_csf, **kwargs): self.norb = norb self.nelec = nelec self.check_transformer_cache () return get_init_guess (norb, nelec, nroots, hdiag_csf, self.transformer) def make_hdiag_csf (self, h1e, eri, norb, nelec, hdiag_det=None): self.norb = norb self.nelec = nelec self.check_transformer_cache () return make_hdiag_csf (h1e, eri, norb, nelec, self.transformer, hdiag_det=hdiag_det) make_hdiag = make_hdiag_det def absorb_h1e (self, h1e, eri, norb, nelec, fac=1): h1e_c, h1e_s = unpack_h1e_cs (h1e) h2eff = super().absorb_h1e (h1e_c, eri, norb, nelec, fac) if h1e_s is not None: h2eff = tag_array (h2eff, h1e_s=h1e_s) return h2eff def contract_2e(self, eri, fcivec, norb, nelec, link_index=None, **kwargs): hc = super().contract_2e(eri, fcivec, norb, nelec, link_index, **kwargs) if hasattr (eri, 'h1e_s'): hc += direct_uhf.contract_1e ([eri.h1e_s, -eri.h1e_s], fcivec, norb, nelec, link_index) return hc ''' 01/14/2019: Changing strategy; I'm now replacing the kernel and pspace functions instead of make_precond and eig ''' def pspace (self, h1e, eri, norb, nelec, hdiag_det=None, hdiag_csf=None, npsp=200, **kwargs): self.norb = norb self.nelec = nelec self.check_transformer_cache () return pspace (self, h1e, eri, norb, nelec, self.transformer, hdiag_det=hdiag_det, hdiag_csf=hdiag_csf, npsp=npsp) def kernel(self, h1e, eri, norb, nelec, ci0=None, **kwargs): self.norb = norb self.nelec = nelec if 'smult' in kwargs: self.smult = kwargs['smult'] kwargs.pop ('smult') self.check_transformer_cache () e, c = kernel (self, h1e, eri, norb, nelec, smult=self.smult, idx_sym=None, ci0=ci0, transformer=self.transformer, **kwargs) self.eci, self.ci = e, c return e, c def check_transformer_cache (self): assert (isinstance (self.smult, (int, np.number))) neleca, nelecb = _unpack_nelec (self.nelec) if self.transformer is None: self.transformer = CSFTransformer (self.norb, neleca, nelecb, self.smult) else: self.transformer._update_spin_cache (self.norb, neleca, nelecb, self.smult)
class FCISolver(direct_spin1_symm.FCISolver): r''' get_init_guess uses csfstring.py and csdstring.py to construct a spin-symmetry-adapted initial guess, and the Davidson algorithm is carried out in the CSF basis. However, the ci attribute is put in the determinant basis at the end of it all, and "ci0" is also assumed to be in the determinant basis. ...However, I want to also do point-group symmetry better than direct_spin1_symm... ''' pspace_size = getattr(__config__, 'fci_csf_FCI_pspace_size', 200) def __init__(self, mol=None, smult=None): self.smult = smult self.transformer = None super().__init__(mol) make_hdiag = make_hdiag_det def absorb_h1e(self, h1e, eri, norb, nelec, fac=1): h1e_c, h1e_s = unpack_h1e_cs(h1e) h2eff = super().absorb_h1e(h1e_c, eri, norb, nelec, fac) if h1e_s is not None: h2eff = tag_array(h2eff, h1e_s=h1e_s) return h2eff def contract_2e(self, eri, fcivec, norb, nelec, link_index=None, **kwargs): hc = super().contract_2e(eri, fcivec, norb, nelec, link_index, **kwargs) if hasattr(eri, 'h1e_s'): hc += direct_uhf.contract_1e([eri.h1e_s, -eri.h1e_s], fcivec, norb, nelec, link_index) return hc def make_hdiag_csf(self, h1e, eri, norb, nelec, hdiag_det=None): self.norb, self.nelec = norb, nelec self.check_transformer_cache() return make_hdiag_csf(h1e, eri, norb, nelec, self.transformer, hdiag_det=hdiag_det) def pspace(self, h1e, eri, norb, nelec, hdiag_det=None, hdiag_csf=None, npsp=200, **kwargs): self.norb, self.nelec = norb, nelec self.check_transformer_cache() return pspace(self, h1e, eri, norb, nelec, self.transformer, hdiag_det=hdiag_det, hdiag_csf=hdiag_csf, npsp=npsp) def kernel(self, h1e, eri, norb, nelec, ci0=None, **kwargs): ''' Over the top of the existing kernel, I just need to set the parameters and cache values related to spin. ...and electron configuration point group ''' if 'nroots' not in kwargs: nroots = self.nroots kwargs['nroots'] = nroots orbsym_back = self.orbsym if 'orbsym' not in kwargs: kwargs['orbsym'] = self.orbsym orbsym = kwargs['orbsym'] wfnsym_back = self.wfnsym if 'wfnsym' not in kwargs: wfnsym = self.wfnsym kwargs['wfnsym'] = wfnsym if self.verbose >= logger.WARN: self.check_sanity() self.norb = norb self.nelec = nelec if 'smult' in kwargs: self.smult = kwargs['smult'] kwargs.pop('smult') # The order of the four things below is super sensitive self.orbsym = orbsym wfnsym = self.guess_wfnsym(norb, nelec, ci0, **kwargs) self.wfnsym = wfnsym kwargs['wfnsym'] = wfnsym self.check_transformer_cache() idx_sym = self.transformer.confsym[ self.transformer.econf_csf_mask] == wfnsym e, c = kernel(self, h1e, eri, norb, nelec, smult=self.smult, idx_sym=idx_sym, ci0=ci0, transformer=self.transformer, **kwargs) self.eci, self.ci = e, c self.orbsym = orbsym_back self.wfnsym = wfnsym_back return e, c def get_init_guess(self, norb, nelec, nroots, hdiag_csf, **kwargs): orbsym = kwargs['orbsym'] if 'orbsym' in kwargs else self.orbsym wfnsym = kwargs['wfnsym'] if 'wfnsym' in kwargs else self.wfnsym self.orbsym = orbsym self.wfnsym = wfnsym assert ((self.orbsym is not None) and (self.wfnsym is not None)) self.norb = norb self.nelec = nelec self.check_transformer_cache() return get_init_guess(norb, nelec, nroots, hdiag_csf, self.transformer) 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