def get_occ(self, mo_energy, mo_coeff=None): ''' We cannot assume default mo_energy value, because the orbital energies are sorted after doing SCF. But in this function, we need the orbital energies are grouped by symmetry irreps ''' mol = self.mol nirrep = len(mol.symm_orb) if mo_coeff is not None: orbsym = symm.label_orb_symm(self, mol.irrep_id, mol.symm_orb, mo_coeff, self.get_ovlp(), False) orbsym = numpy.asarray(orbsym) else: orbsym = [numpy.repeat(ir, mol.symm_orb[i].shape[1]) for i, ir in enumerate(mol.irrep_id)] orbsym = numpy.hstack(orbsym) mo_occ = numpy.zeros_like(mo_energy) mo_e_left = [] idx_e_left = [] nelec_fix = 0 for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] ir_idx = numpy.where(orbsym == ir)[0] if irname in self.irrep_nelec: n = self.irrep_nelec[irname] e_idx = numpy.argsort(mo_energy[ir_idx]) mo_occ[ir_idx[e_idx[:n//2]]] = 2 nelec_fix += n else: idx_e_left.append(ir_idx) nelec_float = mol.nelectron - nelec_fix assert(nelec_float >= 0) if nelec_float > 0: idx_e_left = numpy.hstack(idx_e_left) mo_e_left = mo_energy[idx_e_left] mo_e_sort = numpy.argsort(mo_e_left) occ_idx = idx_e_left[mo_e_sort[:(nelec_float//2)]] mo_occ[occ_idx] = 2 viridx = (mo_occ==0) if self.verbose < logger.INFO or viridx.sum() == 0: return mo_occ ehomo = max(mo_energy[mo_occ>0 ]) elumo = min(mo_energy[mo_occ==0]) noccs = [] for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] ir_idx = (orbsym == ir) noccs.append(int(mo_occ[ir_idx].sum())) if ehomo in mo_energy[ir_idx]: irhomo = irname if elumo in mo_energy[ir_idx]: irlumo = irname logger.info(self, 'H**O (%s) = %.15g LUMO (%s) = %.15g', irhomo, ehomo, irlumo, elumo) if self.verbose >= logger.DEBUG: logger.debug(self, 'irrep_nelec = %s', noccs) _dump_mo_energy(mol, mo_energy, mo_occ, ehomo, elumo, orbsym) return mo_occ
def build(self, mol=None): if mol is None: mol = self.mol if mol.symmetry: for irname in self.irrep_nelec: if irname not in mol.irrep_name: logger.warn(self, 'Molecule does not have irrep %s', irname) nelec_fix = self.irrep_nelec.values() if any(isinstance(x, (tuple, list)) for x in nelec_fix): msg =('Number of alpha/beta electrons cannot be assigned ' 'separately in GHF. irrep_nelec = %s' % self.irrep_nelec) raise ValueError(msg) nelec_fix = sum(nelec_fix) float_irname = set(mol.irrep_name) - set(self.irrep_nelec) if nelec_fix > mol.nelectron: msg =('More electrons defined by irrep_nelec than total num electrons. ' 'mol.nelectron = %d irrep_nelec = %s' % (mol.nelectron, self.irrep_nelec)) raise ValueError(msg) else: logger.info(mol, 'Freeze %d electrons in irreps %s', nelec_fix, self.irrep_nelec.keys()) if len(float_irname) == 0 and nelec_fix != mol.nelectron: msg =('Num electrons defined by irrep_nelec != total num electrons. ' 'mol.nelectron = %d irrep_nelec = %s' % (mol.nelectron, self.irrep_nelec)) raise ValueError(msg) else: logger.info(mol, ' %d free electrons in irreps %s', mol.nelectron-nelec_fix, ' '.join(float_irname)) return ghf.GHF.build(self, mol)
def init_amps(self, eris): time0 = time.clock(), time.time() mo_e = eris.fock.diagonal() nocc = self.nocc() nvir = mo_e.size - nocc t1 = np.zeros((nocc,nvir), eris.dtype) #eia = mo_e[:nocc,None] - mo_e[None,nocc:] #t1 = eris.fock[:nocc,nocc:] / eia t2 = np.zeros((nocc,nocc,nvir,nvir), eris.dtype) self.emp2 = 0 foo = eris.fock[:nocc,:nocc] fvv = eris.fock[nocc:,nocc:] eia = np.zeros((nocc,nvir)) eijab = np.zeros((nocc,nocc,nvir,nvir)) for i in range(nocc): for a in range(nvir): eia[i,a] = (foo[i,i] - fvv[a,a]).real for j in range(nocc): for b in range(nvir): eijab[i,j,a,b] = ( foo[i,i] + foo[j,j] - fvv[a,a] - fvv[b,b] ).real t2[i,j,a,b] = eris.oovv[i,j,a,b]/eijab[i,j,a,b] eris_oovv = _cp(eris.oovv) self.emp2 = 0.25*einsum('ijab,ijab',t2,eris_oovv.conj()).real logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def build_(self): mol = self.mol self.orth_coeff = self.get_orth_ao(mol) self.bas_on_frag = select_ao_on_fragment(mol, self.imp_atoms, \ self.imp_basidx) c_inv = numpy.dot(self.orth_coeff.T, self.entire_scf.get_ovlp(self.mol)) mo_a, mo_b = self.entire_scf.mo_coeff occ_a, occ_b = self.entire_scf.mo_occ mo_orth_a = numpy.dot(c_inv, mo_a[:,self.entire_scf.mo_occ[0]>1e-15]) mo_orth_b = numpy.dot(c_inv, mo_b[:,self.entire_scf.mo_occ[1]>1e-15]) # self.imp_site, self.bath_orb, self.env_orb are based on orth-orbitals self.imp_site, self.bath_orb, self.env_orb = \ self.decompose_orbital((mo_orth_a,mo_orth_b)) ovlp = numpy.dot(self.bath_orb[0].T,self.bath_orb[1])[:4,:4] for i,c in enumerate(ovlp): log.debug(self, ('<bath_alpha_%d|bath_beta> = ' % i) \ + '%10.5f'*len(c), *c) self.impbas_coeff = self.cons_impurity_basis() self.nelectron_alpha = self.entire_scf.nelectron_alpha \ - self.env_orb[0].shape[1] self.nelectron_beta = mol.nelectron \ - self.entire_scf.nelectron_alpha \ - self.env_orb[1].shape[1] log.info(self, 'alpha / beta electrons = %d / %d', \ self.nelectron_alpha, self.nelectron_beta) self.energy_by_env, self._vhf_env = self.init_vhf_env(self.env_orb)
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc() nvir = self.nmo() - nocc nkpts = self.nkpts t1 = numpy.zeros((nkpts,nocc,nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts,nkpts,nkpts,nocc,nocc,nvir,nvir), dtype=numpy.complex128) self.emp2 = 0 foo = eris.fock[:,:nocc,:nocc].copy() fvv = eris.fock[:,nocc:,nocc:].copy() eris_oovv = eris.oovv.copy() eia = numpy.zeros((nocc,nvir)) eijab = numpy.zeros((nocc,nocc,nvir,nvir)) kconserv = tools.get_kconserv(self._scf.cell,self.kpts) for ki in range(nkpts): for kj in range(nkpts): for ka in range(nkpts): kb = kconserv[ki,ka,kj] for i in range(nocc): for a in range(nvir): eia[i,a] = foo[ki,i,i] - fvv[ka,a,a] for j in range(nocc): for b in range(nvir): eijab[i,j,a,b] = ( foo[ki,i,i] + foo[kj,j,j] - fvv[ka,a,a] - fvv[kb,b,b] ) t2[ki,kj,ka,i,j,a,b] = eris_oovv[ki,kj,ka,i,j,a,b]/eijab[i,j,a,b] t2 = numpy.conj(t2) self.emp2 = 0.25*numpy.einsum('pqrijab,pqrijab',t2,eris_oovv).real self.emp2 /= nkpts logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2.real) logger.timer(self, 'init mp2', *time0) print "MP2 energy =", self.emp2 return self.emp2, t1, t2
def kernel(self, h1e, eri, norb, nelec, fciRestart=None, **kwargs): if self.nroots == 1: roots = 0 else: roots = range(self.nroots) if fciRestart is None: fciRestart = self.restart or self._restart writeIntegralFile(self, h1e, eri, norb, nelec) writeDMRGConfFile(self, nelec, fciRestart) if self.verbose >= logger.DEBUG1: inFile = os.path.join(self.runtimeDir, self.configFile) logger.debug1(self, 'Block Input conf') logger.debug1(self, open(inFile, 'r').read()) if self.onlywriteIntegral: logger.info(self, 'Only write integral') try: calc_e = readEnergy(self) except IOError: if self.nroots == 1: calc_e = 0.0 else : calc_e = [0.0] * self.nroots return calc_e, roots executeBLOCK(self) if self.verbose >= logger.DEBUG1: outFile = os.path.join(self.runtimeDir, self.outputFile) logger.debug1(self, open(outFile).read()) calc_e = readEnergy(self) return calc_e, roots
def get_occ(self, mo_energy=None, mo_coeff=None): if mo_energy is None: mo_energy = self.mo_energy mol = self.mol n4c = len(mo_energy) n2c = n4c // 2 mo_occ = numpy.zeros(n2c * 2) if mo_energy[n2c] > -1.999 * mol.light_speed ** 2: mo_occ[n2c : n2c + mol.nelectron] = 1 else: n = 0 for i, e in enumerate(mo_energy): if e > -1.999 * mol.light_speed ** 2 and n < mol.nelectron: mo_occ[i] = 1 n += 1 if self.verbose >= logger.INFO: logger.info( self, "H**O %d = %.12g, LUMO %d = %.12g,", (n2c + mol.nelectron) // 2, mo_energy[n2c + mol.nelectron - 1], (n2c + mol.nelectron) // 2 + 1, mo_energy[n2c + mol.nelectron], ) logger.debug(self, "NES mo_energy = %s", mo_energy[:n2c]) logger.debug(self, "PES mo_energy = %s", mo_energy[n2c:]) return mo_occ
def ccsd(self, t1=None, t2=None, eris=None, mbpt2=False): '''Ground-state unrestricted (U)CCSD. Kwargs: mbpt2 : bool Use one-shot MBPT2 approximation to CCSD. ''' if eris is None: eris = self.ao2mo(self.mo_coeff) self.eris = eris self.dump_flags() if mbpt2: cctyp = 'MBPT2' self.e_corr, self.t1, self.t2 = self.init_amps(eris) else: cctyp = 'CCSD' self.converged, self.e_corr, self.t1, self.t2 = \ kernel(self, eris, t1, t2, max_cycle=self.max_cycle, tol=self.conv_tol, tolnormt=self.conv_tol_normt, verbose=self.verbose) if self.converged: logger.info(self, 'CCSD converged') else: logger.info(self, 'CCSD not converged') if self._scf.e_tot == 0: logger.note(self, 'E_corr = %.16g', self.e_corr) else: logger.note(self, 'E(%s) = %.16g E_corr = %.16g', cctyp, self.e_tot, self.e_corr) return self.e_corr, self.t1, self.t2
def get_occ(mo_energy_kpts=None, mo_coeff=None): if mo_energy_kpts is None: mo_energy_kpts = mf.mo_energy if nelec is None: cell_nelec = mf.cell.nelec else: cell_nelec = nelec h**o=[-1e8,-1e8] lumo=[1e8,1e8] mo_occ_kpts = [[], []] for s in [0,1]: for k, mo_energy in enumerate(mo_energy_kpts[s]): e_idx = numpy.argsort(mo_energy) e_sort = mo_energy[e_idx] n = cell_nelec[s] mo_occ = numpy.zeros_like(mo_energy) mo_occ[e_idx[:n]] = 1 h**o[s] = max(h**o[s], e_sort[n-1]) lumo[s] = min(lumo[s], e_sort[n]) mo_occ_kpts[s].append(mo_occ) for nm,s in zip(['alpha','beta'],[0,1]): logger.info(mf, nm+' H**O = %.12g LUMO = %.12g', h**o[s], lumo[s]) if h**o[s] > lumo[s]: logger.warn(mf, "WARNING! H**O is greater than LUMO! " "This may lead to incorrect canonical occupation.") return mo_occ_kpts
def get_occ(mf, mo_energy=None, mo_coeff=None): '''Label the occupancies for each orbital. NOTE the occupancies are not assigned based on the orbital energy ordering. The first N orbitals are assigned to be occupied orbitals. Examples: >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1) >>> mf = scf.hf.SCF(mol) >>> energy = numpy.array([-10., -1., 1, -2., 0, -3]) >>> mf.get_occ(energy) array([2, 2, 2, 2, 1, 0]) ''' if mo_energy is None: mo_energy = mf.mo_energy if getattr(mo_energy, 'mo_ea', None) is not None: mo_ea = mo_energy.mo_ea mo_eb = mo_energy.mo_eb else: mo_ea = mo_eb = mo_energy nmo = mo_ea.size mo_occ = numpy.zeros(nmo) if getattr(mf, 'nelec', None) is None: nelec = mf.mol.nelec else: nelec = mf.nelec ncore = nelec[1] nocc = nelec[0] nopen = abs(nocc - ncore) mo_occ = _fill_rohf_occ(mo_energy, mo_ea, mo_eb, ncore, nopen) if mf.verbose >= logger.INFO and nocc < nmo and ncore > 0: ehomo = max(mo_energy[mo_occ> 0]) elumo = min(mo_energy[mo_occ==0]) if ehomo+1e-3 > elumo: logger.warn(mf, 'H**O %.15g >= LUMO %.15g', ehomo, elumo) else: logger.info(mf, ' H**O = %.15g LUMO = %.15g', ehomo, elumo) if nopen > 0 and mf.verbose >= logger.DEBUG: core_idx = mo_occ == 2 open_idx = mo_occ == 1 vir_idx = mo_occ == 0 logger.debug(mf, ' Roothaan | alpha | beta') logger.debug(mf, ' Highest 2-occ = %18.15g | %18.15g | %18.15g', max(mo_energy[core_idx]), max(mo_ea[core_idx]), max(mo_eb[core_idx])) logger.debug(mf, ' Lowest 0-occ = %18.15g | %18.15g | %18.15g', min(mo_energy[vir_idx]), min(mo_ea[vir_idx]), min(mo_eb[vir_idx])) for i in numpy.where(open_idx)[0]: logger.debug(mf, ' 1-occ = %18.15g | %18.15g | %18.15g', mo_energy[i], mo_ea[i], mo_eb[i]) if mf.verbose >= logger.DEBUG: numpy.set_printoptions(threshold=nmo) logger.debug(mf, ' Roothaan mo_energy =\n%s', mo_energy) logger.debug1(mf, ' alpha mo_energy =\n%s', mo_ea) logger.debug1(mf, ' beta mo_energy =\n%s', mo_eb) numpy.set_printoptions(threshold=1000) return mo_occ
def init_amps(self, eris=None): time0 = time.clock(), time.time() if eris is None: eris = self.ao2mo(self.mo_coeff) nocca, noccb = self.nocc fova = eris.focka[:nocca,nocca:] fovb = eris.fockb[:noccb,noccb:] mo_ea_o = eris.mo_energy[0][:nocca] mo_ea_v = eris.mo_energy[0][nocca:] mo_eb_o = eris.mo_energy[1][:noccb] mo_eb_v = eris.mo_energy[1][noccb:] eia_a = lib.direct_sum('i-a->ia', mo_ea_o, mo_ea_v) eia_b = lib.direct_sum('i-a->ia', mo_eb_o, mo_eb_v) t1a = fova.conj() / eia_a t1b = fovb.conj() / eia_b eris_ovov = np.asarray(eris.ovov) eris_OVOV = np.asarray(eris.OVOV) eris_ovOV = np.asarray(eris.ovOV) t2aa = eris_ovov.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_a, eia_a) t2ab = eris_ovOV.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_a, eia_b) t2bb = eris_OVOV.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_b, eia_b) t2aa = t2aa - t2aa.transpose(0,1,3,2) t2bb = t2bb - t2bb.transpose(0,1,3,2) e = np.einsum('iJaB,iaJB', t2ab, eris_ovOV) e += 0.25*np.einsum('ijab,iajb', t2aa, eris_ovov) e -= 0.25*np.einsum('ijab,ibja', t2aa, eris_ovov) e += 0.25*np.einsum('ijab,iajb', t2bb, eris_OVOV) e -= 0.25*np.einsum('ijab,ibja', t2bb, eris_OVOV) self.emp2 = e.real logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2) logger.timer(self, 'init mp2', *time0) return self.emp2, (t1a,t1b), (t2aa,t2ab,t2bb)
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc() nvir = self.nmo() - nocc nkpts = self.nkpts t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) woovv = numpy.empty((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 foo = eris.fock[:, :nocc, :nocc].copy() fvv = eris.fock[:, nocc:, nocc:].copy() eris_oovv = eris.oovv.copy() eia = numpy.zeros((nocc, nvir)) eijab = numpy.zeros((nocc, nocc, nvir, nvir)) kconserv = self.kconserv for ki in range(nkpts): for kj in range(nkpts): for ka in range(nkpts): kb = kconserv[ki, ka, kj] eia = np.diagonal(foo[ki]).reshape(-1, 1) - np.diagonal(fvv[ka]) ejb = np.diagonal(foo[kj]).reshape(-1, 1) - np.diagonal(fvv[kb]) eijab = lib.direct_sum("ia,jb->ijab", eia, ejb) woovv[ki, kj, ka] = 2 * eris_oovv[ki, kj, ka] - eris_oovv[ki, kj, kb].transpose(0, 1, 3, 2) t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = numpy.einsum("pqrijab,pqrijab", t2, woovv).real self.emp2 /= nkpts logger.info(self, "Init t2, MP2 energy = %.15g", self.emp2) logger.timer(self, "init mp2", *time0) return self.emp2, t1, t2
def remove_linear_dep_(mf, threshold=LINEAR_DEP_THRESHOLD, lindep=LINEAR_DEP_TRIGGER): ''' Args: threshold : float The threshold under which the eigenvalues of the overlap matrix are discarded to avoid numerical instability. lindep : float The threshold that triggers the special treatment of the linear dependence issue. ''' s = mf.get_ovlp() cond = numpy.max(lib.cond(s)) if cond < 1./lindep: return mf logger.info(mf, 'Applying remove_linear_dep_ on SCF obejct.') logger.debug(mf, 'Overlap condition number %g', cond) def eigh(h, s): d, t = numpy.linalg.eigh(s) x = t[:,d>threshold] / numpy.sqrt(d[d>threshold]) xhx = reduce(numpy.dot, (x.T.conj(), h, x)) e, c = numpy.linalg.eigh(xhx) c = numpy.dot(x, c) return e, c mf._eigh = eigh return mf
def energy_calc(self): log.info(self, '==== Calculating DMET E_corr with read-in v_fit ====') mol = self.mol self.init_embsys(mol) emb = self.embs[0] emb.verbose = self.verbose emb.imp_scf() nimp = len(emb.bas_on_frag) print('Correlation potential: ') print(self._init_v) etot, e2frag, dm1 = self.solver.run(emb, emb._eri, self._init_v, with_1pdm=True, with_e2frag=nimp) log.debug(self,'Total energy returned from solver: %.11g',etot) e_tot = etot + emb.energy_by_env e_frag, nelec_frag = self.extract_frag_energy(emb, dm1, e2frag) hfdm = emb.make_rdm1(emb.mo_coeff_on_imp, emb.mo_occ) vhf = emb.get_veff(mol, hfdm) nelechf = hfdm[:nimp].trace() ehfinhf = (hfdm[:nimp]*(emb._pure_hcore)[:nimp]).sum() \ + (hfdm[:nimp]*(vhf+emb._vhf_env)[:nimp]).sum() * .5 log.debug(self, 'without further fitting, e_tot = %.11g, e_frag = %.11g, nelec_frag = %.11g', e_tot, e_frag, nelec_frag) log.debug(self, ' HF-in-HF, frag energy = %.12g, nelec = %.9g', ehfinhf, nelechf) log.debug(self, ' FCI-in-HF, frag energy = %.12g, E_corr = %.12g, nelec = %.9g', \ e_frag, e_frag-ehfinhf, nelec_frag) log.log(self, 'dmet_nonsc.energy_calc: e_tot = %.11g, (+nuc=%.11g)', \ e_tot, e_tot+mol.energy_nuc()) log.log(self, 'e_frag = %.11g, nelec_frag = %.11g', e_frag, nelec_frag) return e_tot
def get_occ(mo_energy=None, mo_coeff=None): if mo_energy is None: mo_energy = mf.mo_energy if mo_coeff is None: mo_coeff = mf.mo_coeff if isinstance(mf, pyscf.scf.rohf.ROHF): mo_coeff = numpy.array([mo_coeff, mo_coeff]) mo_occ = numpy.zeros_like(setocc) nocc_a = int(numpy.sum(setocc[0])) nocc_b = int(numpy.sum(setocc[1])) s_a = reduce(numpy.dot, (coef_occ_a.T, mf.get_ovlp(), mo_coeff[0])) s_b = reduce(numpy.dot, (coef_occ_b.T, mf.get_ovlp(), mo_coeff[1])) #choose a subset of mo_coeff, which maximizes <old|now> idx_a = numpy.argsort(numpy.einsum('ij,ij->j', s_a, s_a)) idx_b = numpy.argsort(numpy.einsum('ij,ij->j', s_b, s_b)) mo_occ[0][idx_a[-nocc_a:]] = 1. mo_occ[1][idx_b[-nocc_b:]] = 1. if mf.verbose >= logger.DEBUG: logger.info(mf, ' New alpha occ pattern: %s', mo_occ[0]) logger.info(mf, ' New beta occ pattern: %s', mo_occ[1]) if mf.verbose >= logger.DEBUG1: if mo_energy.ndim == 2: logger.info(mf, ' Current alpha mo_energy(sorted) = %s', mo_energy[0]) logger.info(mf, ' Current beta mo_energy(sorted) = %s', mo_energy[1]) elif mo_energy.ndim == 1: logger.info(mf, ' Current mo_energy(sorted) = %s', mo_energy) if (int(numpy.sum(mo_occ[0])) != nocc_a): log.error(self, 'mom alpha electron occupation numbers do not match: %d, %d', nocc_a, int(numpy.sum(mo_occ[0]))) if (int(numpy.sum(mo_occ[1])) != nocc_b): log.error(self, 'mom alpha electron occupation numbers do not match: %d, %d', nocc_b, int(numpy.sum(mo_occ[1]))) #output 1-dimension occupation number for restricted open-shell if isinstance(mf, pyscf.scf.rohf.ROHF): mo_occ = mo_occ[0, :] + mo_occ[1, :] return mo_occ
def kernel(self, mo_coeff=None, ci=None, atmlst=None, mf_grad=None, state=None, verbose=None): cput0 = (time.clock(), time.time()) log = logger.new_logger(self, verbose) if ci is None: ci = self.base.ci if isinstance(ci, (list, tuple)): if state is None: state = self.state else: self.state = state ci = ci[state] logger.info(self, 'Multiple roots are found in CASCI solver. ' 'Nuclear gradients of root %d are computed.', state) if atmlst is None: atmlst = self.atmlst else: self.atmlst = atmlst if self.verbose >= logger.WARN: self.check_sanity() if self.verbose >= logger.INFO: self.dump_flags() self.de = kernel(self.base, mo_coeff, ci, atmlst, mf_grad, log) log.timer('CASCI gradients', *cput0) self._finalize() return self.de
def get_jk(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() t0 = (time.clock(), time.time()) verbose_bak, mol.verbose = mol.verbose, self.verbose stdout_bak, mol.stdout = mol.stdout , self.stdout if self.direct_scf and self.opt[0] is None: self.opt = self.init_direct_scf(mol) opt_llll, opt_ssll, opt_ssss, opt_gaunt = self.opt vj, vk = get_jk_coulomb(mol, dm, hermi, self._coulomb_now, opt_llll, opt_ssll, opt_ssss) if self.with_breit: if 'SSSS' in self._coulomb_now.upper() or not self.with_ssss: vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, True) logger.info(self, 'Add Breit term') vj += vj1 vk += vk1 elif self.with_gaunt and 'SS' in self._coulomb_now.upper(): logger.info(self, 'Add Gaunt term') vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, False) vj += vj1 vk += vk1 mol.verbose = verbose_bak mol.stdout = stdout_bak logger.timer(self, 'vj and vk', *t0) return vj, vk
def dump_flags(self, verbose=None): direct_spin1.FCISolver.dump_flags(self, verbose) if isinstance(self.wfnsym, str): logger.info(self, 'specified total symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.integer)): logger.info(self, 'specified total symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym))
def get_occ(self, mo_energy=None, mo_coeff=None): '''Label the occupancies for each orbital Kwargs: mo_energy : 1D ndarray Obital energies mo_coeff : 2D ndarray Obital coefficients Examples: >>> from pyscf import gto, scf >>> mol = gto.M(atom='H 0 0 0; F 0 0 1.1') >>> mf = scf.hf.SCF(mol) >>> mf.get_occ(numpy.arange(mol.nao_nr())) array([2, 2, 2, 2, 2, 0]) ''' if mo_energy is None: mo_energy = self.mo_energy mo_occ = numpy.zeros_like(mo_energy) nocc = self.mol.nelectron // 2 mo_occ[:nocc] = 2 if nocc < mo_occ.size: logger.info(self, 'H**O = %.12g, LUMO = %.12g,', mo_energy[nocc-1], mo_energy[nocc]) if mo_energy[nocc-1]+1e-3 > mo_energy[nocc]: logger.warn(self, '!! H**O %.12g == LUMO %.12g', mo_energy[nocc-1], mo_energy[nocc]) else: logger.info(self, 'H**O = %.12g,', mo_energy[nocc-1]) if self.verbose >= logger.DEBUG: numpy.set_printoptions(threshold=len(mo_energy)) logger.debug(self, ' mo_energy = %s', mo_energy) numpy.set_printoptions() return mo_occ
def get_init_guess(self, mol=None, key='minao'): if mol is None: mol = self.mol if callable(key): dm = key(mol) elif key.lower() == '1e': dm = self.init_guess_by_1e(mol) elif getattr(mol, 'natm', 0) == 0: logger.info(self, 'No atom found in mol. Use 1e initial guess') dm = self.init_guess_by_1e(mol) elif key.lower() == 'atom': dm = self.init_guess_by_atom(mol) elif key.lower() == 'chkfile': try: dm = self.init_guess_by_chkfile() except (IOError, KeyError): logger.warn(self, 'Fail in reading %s. Use MINAO initial guess', self.chkfile) dm = self.init_guess_by_minao(mol) else: dm = self.init_guess_by_minao(mol) if self.verbose >= logger.DEBUG1: logger.debug1(self, 'Nelec from initial guess = %g', (dm*self.get_ovlp()).sum().real) return dm
def compress_approx(self,maxM=500, nevptsolver=None, tol=1e-7, stored_integral =False): '''SC-NEVPT2 with compressed perturber Kwargs : maxM : int DMRG bond dimension Examples: >>> mf = gto.M('N 0 0 0; N 0 0 1.4', basis='6-31g').apply(scf.RHF).run() >>> mc = dmrgscf.DMRGSCF(mf, 4, 4).run() >>> NEVPT(mc, root=0).compress_approx(maxM=100).kernel() -0.14058324991532101 ''' #TODO #Some preprocess for compressed perturber if getattr(self.fcisolver, 'nevpt_intermediate', None): logger.info(self, 'Use compressed mps perturber as an approximation') else: msg = 'Compressed mps perturber can be only used with DMRG wave function' logger.error(self, msg) raise RuntimeError(msg) self.nevptsolver = nevptsolver self.maxM = maxM self.tol = tol self.stored_integral = stored_integral self.canonicalized = True self.compressed_mps = True return self
def get_occ(self, mo_energy=None, mo_coeff=None): '''Label the occupancies for each orbital. NOTE the occupancies are not assigned based on the orbital energy ordering. The first N orbitals are assigned to be occupied orbitals. Examples: >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1) >>> mf = scf.hf.SCF(mol) >>> energy = numpy.array([-10., -1., 1, -2., 0, -3]) >>> mf.get_occ(energy) array([2, 2, 2, 2, 1, 0]) ''' if mo_energy is None: mo_energy = self.mo_energy mo_occ = numpy.zeros_like(mo_energy) ncore = self.nelec[1] nopen = self.nelec[0] - ncore nocc = ncore + nopen mo_occ[:ncore] = 2 mo_occ[ncore:nocc] = 1 if nocc < len(mo_energy): logger.info(self, 'H**O = %.12g LUMO = %.12g', mo_energy[nocc-1], mo_energy[nocc]) if mo_energy[nocc-1]+1e-3 > mo_energy[nocc]: logger.warn(self.mol, '!! H**O %.12g == LUMO %.12g', mo_energy[nocc-1], mo_energy[nocc]) else: logger.info(self, 'H**O = %.12g no LUMO', mo_energy[nocc-1]) if nopen > 0: for i in range(ncore, nocc): logger.debug(self, 'singly occupied orbital energy = %.12g', mo_energy[i]) logger.debug(self, ' mo_energy = %s', mo_energy) return mo_occ
def read_energy(fciqmcci): '''Read and return the final RDM energy from a NECI output file. Args: fciqmcci : an instance of :class:`FCIQMCCI` Specifies the FCIQMC calculation. Used to locate the FCIQMC output file. Returns: rdm_energy : float The final RDM energy printed to the output file. ''' out_file = open(os.path.join(fciqmcci.scratchDirectory, fciqmcci.outputFileCurrent), "r") for line in out_file: # Lookup the RDM energy from the output. if "*TOTAL ENERGY* CALCULATED USING THE" in line: rdm_energy = float(line.split()[-1]) break logger.info(fciqmcci, 'Total energy from FCIQMC: %.15f', rdm_energy) out_file.close() return rdm_energy
def compress_approx(self,maxM=500, compress_schedule=None, tol=1e-7, stored_integral =False): '''SC-NEVPT2 with compressed perturber Kwargs : maxM : int DMRG bond dimension Examples: >>> mf = gto.M('N 0 0 0; N 0 0 1.4', basis='6-31g').apply(scf.RHF).run() >>> mc = dmrgscf.DMRGSCF(mf, 4, 4).run() >>> NEVPT(mc, root=0).compress_approx(maxM=100).kernel() -0.14058324991532101 ''' #TODO #Some preprocess for compressed perturber if hasattr(self.fcisolver, 'nevpt_intermediate'): logger.info(self, 'Use compressed mps perturber as an aaproximation') else: logger.error(self, 'Compressed mps perturber can be only used for DMRG wave function') exit() from pyscf.dmrgscf.nevpt_mpi import DMRG_COMPRESS_NEVPT if stored_integral: #Stored perturbation integral and read them again. For debugging purpose. DMRG_COMPRESS_NEVPT('nevpt_perturb_integral',maxM= maxM, root= self.root, nevptsolver= compress_schedule, tol= tol) else: DMRG_COMPRESS_NEVPT(self,maxM= maxM, root= self.root, nevptsolver= compress_schedule, tol= tol) self.canonicalized = True self.compressed_mps = True return self
def dump_flags(self): pyscf.scf.uhf.UHF.dump_flags(self) logger.info(self, '******** PBC SCF flags ********') logger.info(self, 'kpt = %s', self.kpt) logger.info(self, 'DF object = %s', self.with_df) logger.info(self, 'Exchange divergence treatment (exxdiv) = %s', self.exxdiv) logger.info(self, 'number electrons alpha = %d beta = %d', *self.nelec)
def frag_mulliken_pop(self): '''Mulliken M_ij = D_ij S_ji, Mulliken chg_i = \sum_j M_ij''' mol = self.mol log.info(self, ' ** Mulliken pop (on impurity basis) **') s1e = mol.intor_symmetric('cint1e_ovlp_sph') c_inv = numpy.dot(self.orth_coeff.T, s1e) c_frag = numpy.dot(c_inv, self.impbas_coeff) dm = self.make_rdm1(self.mo_coeff_on_imp, self.mo_occ) nimp = len(self.bas_on_frag) dm[nimp:] = 0 dm = reduce(numpy.dot, (c_frag, dm, c_frag.T.conj())) pop = dm.diagonal() label = mol.spheric_labels() for i, s in enumerate(label): if s[0] in self.imp_atoms: log.info(self, 'pop of %d%s %s%4s ' % s \ + ' %10.5f' % pop[i]) log.info(self, ' ** Mulliken atomic charges **') chg = numpy.zeros(mol.natm) for i, s in enumerate(label): if s[0] in self.imp_atoms: chg[s[0]] += pop[i] frag_charge = 0 for ia in self.imp_atoms: symb = mol.atom_symbol(ia) nuc = mol.atom_charge(ia) log.info(self, 'charge of %d%s = %10.5f', \ ia, symb, nuc - chg[ia]) frag_charge += nuc - chg[ia] log.info(self, 'charge of embsys = %10.5f', frag_charge)
def assemble_frag_energy(self, mol): e_tot = 0 nelec = 0 e_corr = 0 last_frag = -1 for m, _, _ in self.all_frags: if m != last_frag: emb = self.embs[m] nimp = len(emb.bas_on_frag) _, e2frag, dm1 = \ self.solver.run(emb, emb._eri, emb.vfit_ci, with_1pdm=True, with_e2frag=nimp) e_frag, nelec_frag = \ self.extract_frag_energy(emb, dm1, e2frag) log.debug(self, 'fragment %d FCI-in-HF, frag energy = %.12g, E_corr = %.12g, nelec = %.9g', \ m, e_frag, e_frag-emb._ehfinhf, nelec_frag) e_corr += e_frag-emb._ehfinhf e_tot += e_frag nelec += nelec_frag last_frag = m log.info(self, 'sum(e_frag), e_tot = %.9g, nelec_tot = %.9g', \ e_tot, nelec) return e_tot, e_corr, nelec
def dump_flags(self): rhf_grad.Gradients.dump_flags(self) if callable(self._scf.grids.prune): logger.info(self, 'Grid pruning %s may affect DFT gradients accuracy.' 'Call mf.grids.run(prune=False) to mute grid pruning', self._scf.grids.prune) return self
def assemble_frag_fci_energy(self, mol, dm_ref=0): if len(self.bas_off_frags) == 0: e_tot = 0 nelec = 0 else: if dm_ref is 0: eff_scf = self.entire_scf sc = numpy.dot(eff_scf.get_ovlp(mol), self.orth_coeff) mo = numpy.dot(sc.T,eff_scf.mo_coeff) dm_ref = eff_scf.make_rdm1(mo, eff_scf.mo_occ) e_tot, nelec = self.off_frags_energy(mol, dm_ref) last_frag = -1 for m, _, _ in self.all_frags: if m != last_frag: emb = self.embs[m] nimp = len(emb.bas_on_frag) _, e2frag, dm1 = \ self.solver.run(emb, emb._eri, emb.vfit_ci, with_1pdm=True, with_e2frag=nimp) e_frag, nelec_frag = \ self.extract_frag_energy(emb, dm1, e2frag) log.debug(self, 'e_frag = %.12g, nelec_frag = %.12g', \ e_frag, nelec_frag) e_tot += e_frag nelec += nelec_frag last_frag = m log.info(self, 'DMET-FCI-in-HF of entire system, e_tot = %.9g, nelec_tot = %.9g', \ e_tot, nelec) return e_tot, nelec
def init_guess_by_1e(self, mol=None): if mol is None: mol = self.mol logger.info(self, 'Initial guess from hcore.') h1e = self.get_hcore(mol) s1e = self.get_ovlp(mol) mo_energy, mo_coeff = hf.RHF.eig(self, h1e, s1e) mo_occ = self.get_occ(mo_energy, mo_coeff) return self.make_rdm1(mo_coeff, mo_occ)
def dump_flags(self, verbose=None): direct_spin1.FCISolver.dump_flags(self, verbose) logger.info(self, 'ci_coeff_cutoff %g', self.ci_coeff_cutoff) logger.info(self, 'select_cutoff %g', self.select_cutoff)
def eeccsd(self, nroots=1, koopmans=False, guess=None, partition=None): '''Calculate N-electron neutral excitations via EE-EOM-CCSD. Kwargs: nroots : int Number of roots (eigenvalues) requested partition : bool or str Use a matrix-partitioning for the doubles-doubles block. Can be None, 'mp' (Moller-Plesset, i.e. orbital energies on the diagonal), or 'full' (full diagonal elements). koopmans : bool Calculate Koopmans'-like (1p1h) excitations only, targeting via overlap. guess : list of ndarray List of guess vectors to use for targeting via overlap. ''' cput0 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) size = self.nee() nroots = min(nroots, size) if partition: partition = partition.lower() assert partition in ['mp', 'full'] self.ee_partition = partition if partition == 'full': self._eeccsd_diag_matrix2 = self.vector_to_amplitudes_ee( self.eeccsd_diag())[1] nvir = self.nmo - self.nocc adiag = self.eeccsd_diag() user_guess = False if guess: user_guess = True assert len(guess) == nroots for g in guess: assert g.size == size else: guess = [] idx = adiag.argsort() n = 0 for i in idx: g = np.zeros(size) g[i] = 1.0 if koopmans: if np.linalg.norm(g[:self.nocc * nvir])**2 > 0.8: guess.append(g) n += 1 else: guess.append(g) n += 1 if n == nroots: break def precond(r, e0, x0): return r / (e0 - adiag + 1e-12) eig = linalg_helper.eig if user_guess or koopmans: def pickeig(w, v, nr, envs): x0 = linalg_helper._gen_x0(envs['v'], envs['xs']) idx = np.argmax(np.abs( np.dot(np.array(guess).conj(), np.array(x0).T)), axis=1) return w[idx].real, v[:, idx].real, idx eee, evecs = eig(self.eeccsd_matvec, guess, precond, pick=pickeig, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) else: eee, evecs = eig(self.eeccsd_matvec, guess, precond, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) self.eee = eee.real if nroots == 1: eee, evecs = [self.eee], [evecs] for n, en, vn in zip(range(nroots), eee, evecs): logger.info(self, 'EE root %d E = %.16g qpwt = %0.6g', n, en, np.linalg.norm(vn[:self.nocc * nvir])**2) log.timer('EE-CCSD', *cput0) if nroots == 1: return eee[0], evecs[0] else: return eee, evecs
def kernel(casscf, mo_coeff, tol=1e-7, conv_tol_grad=None, ci0=None, callback=None, verbose=None, dump_chk=True): if verbose is None: verbose = casscf.verbose log = logger.Logger(casscf.stdout, verbose) cput0 = (time.clock(), time.time()) log.debug('Start 2-step CASSCF') mo = mo_coeff nmo = mo[0].shape[1] ncore = casscf.ncore eris = casscf.ao2mo(mo) e_tot, e_cas, fcivec = casscf.casci(mo, ci0, eris, log, locals()) if casscf.ncas == nmo and not casscf.internal_rotation: return True, e_tot, e_cas, fcivec, mo if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(tol) logger.info(casscf, 'Set conv_tol_grad to %g', conv_tol_grad) conv_tol_ddm = conv_tol_grad * 3 conv = False de, elast = e_tot, e_tot totmicro = totinner = 0 casdm1 = (0,0) r0 = None t2m = t1m = log.timer('Initializing 2-step CASSCF', *cput0) imacro = 0 while not conv and imacro < casscf.max_cycle_macro: imacro += 1 njk = 0 t3m = t2m casdm1_old = casdm1 casdm1, casdm2 = casscf.fcisolver.make_rdm12s(fcivec, casscf.ncas, casscf.nelecas) norm_ddm =(numpy.linalg.norm(casdm1[0] - casdm1_old[0]) + numpy.linalg.norm(casdm1[1] - casdm1_old[1])) t3m = log.timer('update CAS DM', *t3m) max_cycle_micro = 1 # casscf.micro_cycle_scheduler(locals()) max_stepsize = casscf.max_stepsize_scheduler(locals()) for imicro in range(max_cycle_micro): rota = casscf.rotate_orb_cc(mo, lambda:fcivec, lambda:casdm1, lambda:casdm2, eris, r0, conv_tol_grad*.3, max_stepsize, log) u, g_orb, njk1, r0 = next(rota) rota.close() njk += njk1 norm_t = numpy.linalg.norm(u-numpy.eye(nmo)) norm_gorb = numpy.linalg.norm(g_orb) if imicro == 0: norm_gorb0 = norm_gorb t3m = log.timer('orbital rotation', *t3m) eris = None u = copy.copy(u) g_orb = copy.copy(g_orb) mo = casscf.rotate_mo(mo, u, log) eris = casscf.ao2mo(mo) t3m = log.timer('update eri', *t3m) log.debug('micro %d |u-1|=%5.3g |g[o]|=%5.3g |dm1|=%5.3g', imicro, norm_t, norm_gorb, norm_ddm) if callable(callback): callback(locals()) t2m = log.timer('micro iter %d'%imicro, *t2m) if norm_t < 1e-4 or norm_gorb < conv_tol_grad*.5: break totinner += njk totmicro += imicro+1 e_tot, e_cas, fcivec = casscf.casci(mo, fcivec, eris, log, locals()) log.timer('CASCI solver', *t3m) t2m = t1m = log.timer('macro iter %d'%imacro, *t1m) de, elast = e_tot - elast, e_tot if (abs(de) < tol and norm_gorb < conv_tol_grad and norm_ddm < conv_tol_ddm): conv = True if dump_chk: casscf.dump_chk(locals()) if callable(callback): callback(locals()) if conv: log.info('2-step CASSCF converged in %d macro (%d JK %d micro) steps', imacro+1, totinner, totmicro) else: log.info('2-step CASSCF not converged, %d macro (%d JK %d micro) steps', imacro+1, totinner, totmicro) log.timer('2-step CASSCF', *cput0) return conv, e_tot, e_cas, fcivec, mo
def dump_flags(self, verbose=None): logger.info(self, '\n') logger.info(self, '******** PBC CC flags ********') gccsd.GCCSD.dump_flags(self, verbose) return self
def dump_flags(self, verbose=None): hf.SCF.dump_flags(self, verbose) logger.info(self, 'number electrons alpha = %d beta = %d', *self.nelec)
def check_irrep_nelec(mol, irrep_nelec, nelec): for irname in irrep_nelec: if irname not in mol.irrep_name: logger.warn(mol, 'Molecule does not have irrep %s', irname) float_irname = [] fix_na = 0 fix_nb = 0 free_irrep_norbs = [] for i, irname in enumerate(mol.irrep_name): if irname in irrep_nelec: if isinstance(irrep_nelec[irname], (int, numpy.integer)): nelecb = irrep_nelec[irname] // 2 neleca = irrep_nelec[irname] - nelecb else: neleca, nelecb = irrep_nelec[irname] norb = mol.symm_orb[i].shape[1] if neleca > norb or nelecb > norb: msg = ('More electrons than orbitals for irrep %s ' 'nelec = %d + %d, norb = %d' % (irname, neleca, nelecb, norb)) raise ValueError(msg) fix_na += neleca fix_nb += nelecb else: float_irname.append(irname) free_irrep_norbs.append(mol.symm_orb[i].shape[1]) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec fix_ne = fix_na + fix_nb float_neleca = neleca - fix_na float_nelecb = nelecb - fix_nb free_norb = sum(free_irrep_norbs) if ((fix_na > neleca) or (fix_nb > nelecb) or (fix_na + nelecb > mol.nelectron) or (fix_nb + neleca > mol.nelectron)): msg = ( 'More electrons defined by irrep_nelec than total num electrons. ' 'mol.nelectron = %d irrep_nelec = %s' % (mol.nelectron, irrep_nelec)) raise ValueError(msg) else: logger.info(mol, 'Freeze %d electrons in irreps %s', fix_ne, list(irrep_nelec.keys())) if len(set(float_irname)) == 0 and fix_ne != mol.nelectron: msg = ('Num electrons defined by irrep_nelec != total num electrons. ' 'mol.nelectron = %d irrep_nelec = %s' % (mol.nelectron, irrep_nelec)) raise ValueError(msg) elif float_neleca > free_norb or float_nelecb > free_norb: raise ValueError( 'Not enough orbitals for (%d, %d) electrons in irreps %s ' '(irrep_norb: %s)' % (float_neleca, float_nelecb, ' '.join(float_irname), free_norb)) else: logger.info(mol, ' %d free electrons in irreps %s', mol.nelectron - fix_ne, ' '.join(float_irname)) return fix_na, fix_nb, float_irname
def dump_flags(self, verbose=None): ragf2.RAGF2.dump_flags(self, verbose=verbose) logger.info(self, 'nmom = %s', repr(self.nmom)) return self
def kernel(casscf, mo_coeff, tol=1e-7, conv_tol_grad=None, ci0=None, callback=None, verbose=None, dump_chk=True): from pyscf.mcscf.addons import StateAverageMCSCFSolver if verbose is None: verbose = casscf.verbose if callback is None: callback = casscf.callback log = logger.Logger(casscf.stdout, verbose) cput0 = (logger.process_clock(), logger.perf_counter()) log.debug('Start 2-step CASSCF') mo = mo_coeff nmo = mo.shape[1] ncore = casscf.ncore ncas = casscf.ncas nocc = ncore + ncas eris = casscf.ao2mo(mo) e_tot, e_cas, fcivec = casscf.casci(mo, ci0, eris, log, locals()) if ncas == nmo and not casscf.internal_rotation: if casscf.canonicalization: log.debug('CASSCF canonicalization') mo, fcivec, mo_energy = casscf.canonicalize( mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, verbose=log) else: mo_energy = None return True, e_tot, e_cas, fcivec, mo, mo_energy if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(tol) logger.info(casscf, 'Set conv_tol_grad to %g', conv_tol_grad) conv_tol_ddm = conv_tol_grad * 3 conv = False de, elast = e_tot, e_tot totmicro = totinner = 0 casdm1 = 0 r0 = None t2m = t1m = log.timer('Initializing 2-step CASSCF', *cput0) imacro = 0 while not conv and imacro < casscf.max_cycle_macro: imacro += 1 njk = 0 t3m = t2m casdm1_old = casdm1 casdm1, casdm2 = casscf.fcisolver.make_rdm12(fcivec, ncas, casscf.nelecas) norm_ddm = numpy.linalg.norm(casdm1 - casdm1_old) t3m = log.timer('update CAS DM', *t3m) max_cycle_micro = 1 # casscf.micro_cycle_scheduler(locals()) max_stepsize = casscf.max_stepsize_scheduler(locals()) for imicro in range(max_cycle_micro): rota = casscf.rotate_orb_cc(mo, lambda: fcivec, lambda: casdm1, lambda: casdm2, eris, r0, conv_tol_grad * .3, max_stepsize, log) u, g_orb, njk1, r0 = next(rota) rota.close() njk += njk1 norm_t = numpy.linalg.norm(u - numpy.eye(nmo)) norm_gorb = numpy.linalg.norm(g_orb) if imicro == 0: norm_gorb0 = norm_gorb de = numpy.dot(casscf.pack_uniq_var(u), g_orb) t3m = log.timer('orbital rotation', *t3m) eris = None u = u.copy() g_orb = g_orb.copy() mo = casscf.rotate_mo(mo, u, log) eris = casscf.ao2mo(mo) t3m = log.timer('update eri', *t3m) log.debug( 'micro %d ~dE=%5.3g |u-1|=%5.3g |g[o]|=%5.3g |dm1|=%5.3g', imicro, de, norm_t, norm_gorb, norm_ddm) if callable(callback): callback(locals()) t2m = log.timer('micro iter %d' % imicro, *t2m) if norm_t < 1e-4 or abs( de) < tol * .4 or norm_gorb < conv_tol_grad * .2: break totinner += njk totmicro += imicro + 1 max_offdiag_u = numpy.abs(numpy.triu(u, 1)).max() if max_offdiag_u < casscf.small_rot_tol: small_rot = True log.debug( 'Small orbital rotation, restart CI if supported by solver') else: small_rot = False if not isinstance(casscf, StateAverageMCSCFSolver): # The fcivec from builtin FCI solver is a numpy.ndarray if not isinstance(fcivec, numpy.ndarray): fcivec = small_rot else: newvecs = [] for subvec in fcivec: if not isinstance(subvec, numpy.ndarray): newvecs.append(small_rot) else: newvecs.append(subvec) fcivec = newvecs e_tot, e_cas, fcivec = casscf.casci(mo, fcivec, eris, log, locals()) log.timer('CASCI solver', *t3m) t2m = t1m = log.timer('macro iter %d' % imacro, *t1m) de, elast = e_tot - elast, e_tot if (abs(de) < tol and norm_gorb < conv_tol_grad and norm_ddm < conv_tol_ddm and (max_offdiag_u < casscf.small_rot_tol or casscf.small_rot_tol == 0)): conv = True else: elast = e_tot if dump_chk: casscf.dump_chk(locals()) if callable(callback): callback(locals()) if conv: log.info('2-step CASSCF converged in %d macro (%d JK %d micro) steps', imacro, totinner, totmicro) else: log.info( '2-step CASSCF not converged, %d macro (%d JK %d micro) steps', imacro, totinner, totmicro) if casscf.canonicalization: log.info('CASSCF canonicalization') mo, fcivec, mo_energy = \ casscf.canonicalize(mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, casdm1, log) if casscf.natorb and dump_chk: # dump_chk may save casdm1 occ, ucas = casscf._eig(-casdm1, ncore, nocc) casdm1 = numpy.diag(-occ) else: if casscf.natorb: # FIXME (pyscf-2.0): Whether to transform natural orbitals in # active space when this flag is enabled? log.warn( 'The attribute natorb of mcscf object affects only the ' 'orbital canonicalization.\n' 'If you would like to get natural orbitals in active space ' 'without touching core and external orbitals, an explicit ' 'call to mc.cas_natorb_() is required') mo_energy = None if dump_chk: casscf.dump_chk(locals()) log.timer('2-step CASSCF', *cput0) return conv, e_tot, e_cas, fcivec, mo, mo_energy
def dump_flags(self): ghf.GHF.dump_flags(self) if self.irrep_nelec: logger.info(self, 'irrep_nelec %s', self.irrep_nelec) return self
def init_guess_by_huckel(self, mol=None): if mol is None: mol = self.mol logger.info(self, 'Initial guess from on-the-fly Huckel, doi:10.1021/acs.jctc.8b01089.') return init_guess_by_huckel(mol)
def dump_flags(self, verbose=None): dhf.UHF.dump_flags(self, verbose) logger.info(self, 'XC functionals = %s', self.xc) logger.info(self, 'small_rho_cutoff = %g', self.small_rho_cutoff) self.grids.dump_flags(verbose)
def init_guess_by_atom(self, mol=None): if mol is None: mol = self.mol logger.info(self, 'Initial guess from the superpostion of atomic densties.') return init_guess_by_atom(mol)
def dump_flags(self, verbose=None): hf.SCF.dump_flags(self, verbose) nelec = self.nelec logger.info(self, 'num. doubly occ = %d num. singly occ = %d', nelec[1], nelec[0]-nelec[1])
def get_occ(mf, mo_energy=None, mo_coeff=None): '''Label the occupancies for each orbital. NOTE the occupancies are not assigned based on the orbital energy ordering. The first N orbitals are assigned to be occupied orbitals. Examples: >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1) >>> mf = scf.hf.SCF(mol) >>> energy = numpy.array([-10., -1., 1, -2., 0, -3]) >>> mf.get_occ(energy) array([2, 2, 2, 2, 1, 0]) ''' if mo_energy is None: mo_energy = mf.mo_energy if getattr(mo_energy, 'mo_ea', None) is not None: mo_ea = mo_energy.mo_ea mo_eb = mo_energy.mo_eb else: mo_ea = mo_eb = mo_energy nmo = mo_ea.size mo_occ = numpy.zeros(nmo) if getattr(mf, 'nelec', None) is None: nelec = mf.mol.nelec else: nelec = mf.nelec if nelec[0] > nelec[1]: nocc, ncore = nelec else: ncore, nocc = nelec nopen = nocc - ncore mo_occ = _fill_rohf_occ(mo_energy, mo_ea, mo_eb, ncore, nopen) if mf.verbose >= logger.INFO and nocc < nmo and ncore > 0: ehomo = max(mo_energy[mo_occ> 0]) elumo = min(mo_energy[mo_occ==0]) if ehomo+1e-3 > elumo: logger.warn(mf, 'H**O %.15g >= LUMO %.15g', ehomo, elumo) else: logger.info(mf, ' H**O = %.15g LUMO = %.15g', ehomo, elumo) if nopen > 0 and mf.verbose >= logger.DEBUG: core_idx = mo_occ == 2 open_idx = mo_occ == 1 vir_idx = mo_occ == 0 logger.debug(mf, ' Roothaan | alpha | beta') logger.debug(mf, ' Highest 2-occ = %18.15g | %18.15g | %18.15g', max(mo_energy[core_idx]), max(mo_ea[core_idx]), max(mo_eb[core_idx])) logger.debug(mf, ' Lowest 0-occ = %18.15g | %18.15g | %18.15g', min(mo_energy[vir_idx]), min(mo_ea[vir_idx]), min(mo_eb[vir_idx])) for i in numpy.where(open_idx)[0]: logger.debug(mf, ' 1-occ = %18.15g | %18.15g | %18.15g', mo_energy[i], mo_ea[i], mo_eb[i]) if mf.verbose >= logger.DEBUG: numpy.set_printoptions(threshold=nmo) logger.debug(mf, ' Roothaan mo_energy =\n%s', mo_energy) logger.debug1(mf, ' alpha mo_energy =\n%s', mo_ea) logger.debug1(mf, ' beta mo_energy =\n%s', mo_eb) numpy.set_printoptions(threshold=1000) return mo_occ
def get_occ(self, mo_energy=None, mo_coeff=None): if mo_energy is None: mo_energy = self.mo_energy mol = self.mol if not self.mol.symmetry: return rohf.ROHF.get_occ(self, mo_energy, mo_coeff) if getattr(mo_energy, 'mo_ea', None) is not None: mo_ea = mo_energy.mo_ea mo_eb = mo_energy.mo_eb else: mo_ea = mo_eb = mo_energy nmo = mo_ea.size mo_occ = numpy.zeros(nmo) orbsym = self.get_orbsym(mo_coeff, self.get_ovlp()) rest_idx = numpy.ones(mo_occ.size, dtype=bool) neleca_fix = 0 nelecb_fix = 0 for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] if irname in self.irrep_nelec: ir_idx = numpy.where(orbsym == ir)[0] if isinstance(self.irrep_nelec[irname], (int, numpy.integer)): nelecb = self.irrep_nelec[irname] // 2 neleca = self.irrep_nelec[irname] - nelecb else: neleca, nelecb = self.irrep_nelec[irname] if neleca > nelecb: ncore, nopen = nelecb, neleca - nelecb else: ncore, nopen = neleca, nelecb - neleca mo_occ[ir_idx] = rohf._fill_rohf_occ(mo_energy[ir_idx], mo_ea[ir_idx], mo_eb[ir_idx], ncore, nopen) neleca_fix += neleca nelecb_fix += nelecb rest_idx[ir_idx] = False nelec_float = mol.nelectron - neleca_fix - nelecb_fix assert (nelec_float >= 0) if len(rest_idx) > 0: rest_idx = numpy.where(rest_idx)[0] nopen = abs(mol.spin - (neleca_fix - nelecb_fix)) ncore = (nelec_float - nopen) // 2 mo_occ[rest_idx] = rohf._fill_rohf_occ(mo_energy[rest_idx], mo_ea[rest_idx], mo_eb[rest_idx], ncore, nopen) nocc, ncore = self.nelec nopen = nocc - ncore vir_idx = (mo_occ == 0) if self.verbose >= logger.INFO and nocc < nmo and ncore > 0: ehomo = max(mo_energy[~vir_idx]) elumo = min(mo_energy[vir_idx]) ndoccs = [] nsoccs = [] for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] ir_idx = (orbsym == ir) ndoccs.append(numpy.count_nonzero(mo_occ[ir_idx] == 2)) nsoccs.append(numpy.count_nonzero(mo_occ[ir_idx] == 1)) if ehomo in mo_energy[ir_idx]: irhomo = irname if elumo in mo_energy[ir_idx]: irlumo = irname # to help self.eigh compute orbital energy self._irrep_doccs = ndoccs self._irrep_soccs = nsoccs logger.info(self, 'H**O (%s) = %.15g LUMO (%s) = %.15g', irhomo, ehomo, irlumo, elumo) logger.debug(self, 'double occ irrep_nelec = %s', ndoccs) logger.debug(self, 'single occ irrep_nelec = %s', nsoccs) #_dump_mo_energy(mol, mo_energy, mo_occ, ehomo, elumo, orbsym, # verbose=self.verbose) if nopen > 0: core_idx = mo_occ == 2 open_idx = mo_occ == 1 vir_idx = mo_occ == 0 logger.debug( self, ' Roothaan | alpha | beta' ) logger.debug(self, ' Highest 2-occ = %18.15g | %18.15g | %18.15g', max(mo_energy[core_idx]), max(mo_ea[core_idx]), max(mo_eb[core_idx])) logger.debug(self, ' Lowest 0-occ = %18.15g | %18.15g | %18.15g', min(mo_energy[vir_idx]), min(mo_ea[vir_idx]), min(mo_eb[vir_idx])) for i in numpy.where(open_idx)[0]: logger.debug( self, ' 1-occ = %18.15g | %18.15g | %18.15g', mo_energy[i], mo_ea[i], mo_eb[i]) numpy.set_printoptions(threshold=nmo) logger.debug(self, ' Roothaan mo_energy =\n%s', mo_energy) logger.debug1(self, ' alpha mo_energy =\n%s', mo_ea) logger.debug1(self, ' beta mo_energy =\n%s', mo_eb) numpy.set_printoptions(threshold=1000) return mo_occ
def get_occ(self, mo_energy=None, mo_coeff=None): ''' We assumed mo_energy are grouped by symmetry irreps, (see function self.eig). The orbitals are sorted after SCF. ''' if mo_energy is None: mo_energy = self.mo_energy mol = self.mol if not mol.symmetry: return ghf.GHF.get_occ(self, mo_energy, mo_coeff) orbsym = get_orbsym(mol, mo_coeff) mo_occ = numpy.zeros_like(mo_energy) rest_idx = numpy.ones(mo_occ.size, dtype=bool) nelec_fix = 0 for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] ir_idx = numpy.where(orbsym == ir)[0] if irname in self.irrep_nelec: n = self.irrep_nelec[irname] occ_sort = numpy.argsort(mo_energy[ir_idx].round(9), kind='mergesort') occ_idx = ir_idx[occ_sort[:n]] mo_occ[occ_idx] = 1 nelec_fix += n rest_idx[ir_idx] = False nelec_float = mol.nelectron - nelec_fix assert (nelec_float >= 0) if nelec_float > 0: rest_idx = numpy.where(rest_idx)[0] occ_sort = numpy.argsort(mo_energy[rest_idx].round(9), kind='mergesort') occ_idx = rest_idx[occ_sort[:nelec_float]] mo_occ[occ_idx] = 1 vir_idx = (mo_occ == 0) if self.verbose >= logger.INFO and numpy.count_nonzero(vir_idx) > 0: ehomo = max(mo_energy[~vir_idx]) elumo = min(mo_energy[vir_idx]) noccs = [] for i, ir in enumerate(mol.irrep_id): irname = mol.irrep_name[i] ir_idx = (orbsym == ir) noccs.append(int(mo_occ[ir_idx].sum())) if ehomo in mo_energy[ir_idx]: irhomo = irname if elumo in mo_energy[ir_idx]: irlumo = irname logger.info(self, 'H**O (%s) = %.15g LUMO (%s) = %.15g', irhomo, ehomo, irlumo, elumo) logger.debug(self, 'irrep_nelec = %s', noccs) hf_symm._dump_mo_energy(mol, mo_energy, mo_occ, ehomo, elumo, orbsym, verbose=self.verbose) if mo_coeff is not None and self.verbose >= logger.DEBUG: ss, s = self.spin_square(mo_coeff[:, mo_occ > 0], self.get_ovlp()) logger.debug(self, 'multiplicity <S^2> = %.8g 2S+1 = %.8g', ss, s) return mo_occ
def dump_flags(self, verbose=None): rohf.ROHF.dump_flags(self, verbose) if self.irrep_nelec: logger.info(self, 'irrep_nelec %s', self.irrep_nelec) return self
def dump_flags(self, verbose=None): logger.info(self, '** DFTD3 parameter **') logger.info(self, 'func %s', self.xc) logger.info(self, 'version %s', self.version) return self
def dump_flags(self): hf.SCF.dump_flags(self) logger.info(self, 'with_ssss %s, with_gaunt %s, with_breit %s', self.with_ssss, self.with_gaunt, self.with_breit)
def dump_flags(self): logger.info(self, 'radial grids: %s', self.radi_method.__doc__) logger.info(self, 'becke partition: %s', self.becke_scheme.__doc__) logger.info(self, 'pruning grids: %s', self.prune) logger.info(self, 'grids dens level: %d', self.level) logger.info(self, 'symmetrized grids: %d', self.symmetry) if self.radii_adjust is not None: logger.info(self, 'atomic radii adjust function: %s', self.radii_adjust) logger.debug2(self, 'atomic_radii : %s', self.atomic_radii) if self.atom_grid: logger.info(self, 'User specified grid scheme %s', str(self.atom_grid)) return self
def dump_flags(self, verbose=None): khf.KSCF.dump_flags(self, verbose) logger.info(self, 'number of electrons per unit cell ' 'alpha = %d beta = %d', *self.nelec) return self
def make_moms_hole(mycc, nmom_max_h, t1, t2, l1, l2, ao_repr=False, ns_def=True): ''' Spin-traced one-hole moment in MO basis. mom_h[p,q] = \sum_{sigma} <q_sigma^\dagger (H-E_0)^n p_sigma> ns_def defines the terms according to the Nooijen & Snijders definitions given in IJQC 48 15-48 (1993). The alternate definition simply changes the tensor which is antisymmetrized in the spin integration for products of tensors They should be identical. ''' #partition : bool or str # Use a matrix-partitioning for the doubles-doubles block. # Can be None, 'mp' (Moller-Plesset, i.e. orbital energies on the diagonal), # or 'full' (full diagonal elements). partition = getattr(__config__, 'eom_rccsd_EOM_partition', None) logger.info(mycc, 'partition = %s', partition) #print "Partition value is: ", partition if partition is not None: assert partition.lower() in ['mp','full'] # ns_def breaks sum rules #assert(not ns_def) nocc, nvir = t1.shape nmo = mycc.nmo dtype = np.result_type(t1, t2) vector_size = nocc + nocc*nocc*nvir imds = eom_rccsd._IMDS(mycc) imds.make_ip(partition) diag = ipccsd_diag(imds, partition) theta = t2 * 2 - t2.transpose(0,1,3,2) theta_lam = l2 * 2 - l2.transpose(1,0,2,3) # Construct RHS (b) vector as a_p + [a_p, T] |phi> # Construct LHS (e) vector as <phi|(1+L)(a_q^\dagger + [a_q^\dagger , T]) b_vecs = np.zeros((vector_size, nmo), dtype) e_vecs = np.zeros((vector_size, nmo), dtype) # Improve this so no explicit looping for p in range(nocc): b1 = np.zeros((nocc), dtype) b2 = np.zeros((nocc, nocc, nvir), dtype) e1 = np.zeros((nocc), dtype) e2 = np.zeros((nocc, nocc, nvir), dtype) b1[p] = -1.0 e1[p] = 1. e1 -= np.einsum('ic, c -> i', l1, t1[p,:]) e1 -= np.einsum('jlcd, lcd -> j', l2, theta[p,:,:,:]) if ns_def: # N-S result e2[p,:,:] = 2. * l1[:,:] e2[:,p,:] -= l1[:,:] e2 -= np.einsum('c, ijcb -> ijb', t1[p,:], theta_lam) else: # Result for consistency with pyscf cc-rdm (lambda values antisymmetrized!?) e2[:,p,:] = l1 e2 -= np.einsum('c, jicb -> ijb', t1[p,:], l2) b_vecs[:,p] = amplitudes_to_vector_ip(b1, b2) e_vecs[:,p] = amplitudes_to_vector_ip(e1, e2) for p in range(nvir): b1 = -t1[:,p] if ns_def: b2 = -t2[:,:,p,:] # This is in Nooijen paper else: b2 = -theta[:,:,:,p] e1 = l1[:,p] if ns_def: e2 = theta_lam[:,:,p,:] # This is in Nooijen paper else: e2 = l2[:,:,:,p] b_vecs[:,p+nocc] = amplitudes_to_vector_ip(b1, b2) e_vecs[:,p+nocc] = amplitudes_to_vector_ip(e1, e2) # Now, apply {\bar H} to each b hole_moms = [np.zeros((nmo, nmo)) for i in range(nmom_max_h+1)] # TODO: Would this work for complex? hole_moms[0] = np.dot(e_vecs.T.conj(),b_vecs) hole_moms[0] += hole_moms[0].conj().T #hole_moms[0] = -2.*np.dot(e_vecs.T.conj(),b_vecs) h_RHS = np.zeros_like(b_vecs) for h_app in range(nmom_max_h): if h_app == 0: for p in range(nmo): h_RHS[:,p] = ipccsd_matvec(b_vecs[:,p], imds, diag, nocc, nmo, partition) else: for p in range(nmo): h_RHS[:,p] = ipccsd_matvec(h_RHS[:,p], imds, diag, nocc, nmo, partition) hole_moms[h_app+1] = -np.dot(e_vecs.conj().T,h_RHS) hole_moms[h_app+1] += hole_moms[h_app+1].conj().T if ao_repr: mo = mycc.mo_coeff hole_moms = [lib.einsum('pi,ij,qj->pq', mo, mom, mo.conj()) for mom in hole_moms] return hole_moms
def build(self, quantum_nuc='all', q_nuc_occ=None, **kwargs): '''assign which nuclei are treated quantum mechanically by quantum_nuc (list)''' super().build(self, **kwargs) self.quantum_nuc = [False] * self.natm if quantum_nuc == 'all': self.quantum_nuc = [True] * self.natm logger.info(self, 'All atoms are treated quantum-mechanically by default.') elif isinstance(quantum_nuc, list): for i in quantum_nuc: self.quantum_nuc[i] = True logger.info(self, 'The %s(%i) atom is treated quantum-mechanically' %(self.atom_symbol(i), i)) else: raise TypeError('Unsupported parameter %s' %(quantum_nuc)) self.nuc_num = len([i for i in self.quantum_nuc if i == True]) self.mass = self.atom_mass_list(isotope_avg=True) for i in range(self.natm): if self.atom_symbol(i) == 'H@2': # Deuterium (from Wikipedia) self.mass[i] = 2.01410177811 elif self.atom_symbol(i) == 'H@0': # Muonium (TODO: precise mass) self.mass[i] = 0.114 elif self.atom_pure_symbol(i) == 'H': # Proton (from Wikipedia) self.mass[i] = 1.007276466621 # build the Mole object for electrons and classical nuclei self.elec = gto.Mole() self.elec.super_mol = self self.elec.build(**kwargs) # deal with fractional number of nuclei if q_nuc_occ is not None: q_nuc_occ = numpy.array(q_nuc_occ) if q_nuc_occ.size != self.nuc_num: raise ValueError('q_nuc_occ must match the dimension of quantum_nuc') unocc = numpy.ones_like(q_nuc_occ) - q_nuc_occ unocc_Z = 0 idx = 0 # set all quantum nuclei to have zero charges quantum_nuclear_charge = 0 for i in range(self.natm): if self.quantum_nuc[i] is True: quantum_nuclear_charge -= self.elec._atm[i, 0] if q_nuc_occ is not None: unocc_Z += unocc[idx] * self.elec._atm[i, 0] idx += 1 self.elec._atm[i, 0] = 0 # set nuclear charges of quantum nuclei to 0 self.elec.charge += quantum_nuclear_charge # charge determines the number of electrons if q_nuc_occ is not None: # remove excessive electrons to make the system neutral self.elec.charge += numpy.floor(unocc_Z) self.elec.nhomo = 1.0 - (unocc_Z - numpy.floor(unocc_Z)) else: self.elec.nhomo = None # build a list of Mole objects for quantum nuclei if q_nuc_occ is None: q_nuc_occ = [None] * self.nuc_num idx = 0 for i in range(self.natm): if self.quantum_nuc[i] == True: self.nuc.append(self.build_nuc_mole(i, frac=q_nuc_occ[idx])) idx += 1
def make_moms_part(mycc, nmom_max_p, t1, t2, l1, l2, ao_repr=False): ''' Spin-traced one-particle moment (EA) in MO basis. mom_h[p,q] = \sum_{sigma} <q_sigma (H-E_0)^n p_sigma^\dagger> ''' #partition : bool or str # Use a matrix-partitioning for the doubles-doubles block. # Can be None, 'mp' (Moller-Plesset, i.e. orbital energies on the diagonal), # or 'full' (full diagonal elements). partition = getattr(__config__, 'eom_rccsd_EOM_partition', None) logger.info(mycc, 'partition = %s', partition) #print "Partition value is: ", partition if partition is not None: assert partition.lower() in ['mp','full'] nocc, nvir = t1.shape nmo = mycc.nmo dtype = np.result_type(t1, t2) vector_size = nvir + nocc*nvir*nvir imds = eom_rccsd._IMDS(mycc) imds.make_ea(partition) diag = eaccsd_diag(imds, partition) theta = t2 * 2 - t2.transpose(0,1,3,2) theta_lam = l2 * 2 - l2.transpose(1,0,2,3) # Construct RHS (b) vector as a_p^\dagger + [a_p^\dagger, T] |phi> # Construct LHS (e) vector as <phi|(1+L)(a_q + [a_q , T]) b_vecs = np.zeros((vector_size, nmo), dtype) e_vecs = np.zeros((vector_size, nmo), dtype) # Improve this so no explicit looping for p in range(nocc): b1 = -t1[p,:].copy() b2 = -t2[p,:,:,:].copy() e1 = l1[p,:].copy() e2 = 2.*l2[p,:,:,:].copy() e2 -= l2[:,p,:,:] b_vecs[:,p] = amplitudes_to_vector_ea(b1, b2) e_vecs[:,p] = amplitudes_to_vector_ea(e1, e2) for p in range(nvir): b1 = np.zeros((nvir), dtype) b2 = np.zeros((nocc, nvir, nvir), dtype) e1 = np.zeros((nvir), dtype) e2 = np.zeros((nocc, nvir, nvir), dtype) b1[p] = 1.0 e1[p] = -1.0 e1 += np.einsum('ia,i -> a', l1,t1[:,p]) e1 += 2.*np.einsum('klca,klc -> a',l2, t2[:,:,:,p]) e1 -= np.einsum('klca,lkc -> a',l2, t2[:,:,:,p]) e2[:,p,:] = -2.*l1 e2[:,:,p] += l1 e2 += 2.*np.einsum('k,jkba -> jab', t1[:,p], l2) e2 -= np.einsum('k,jkab -> jab', t1[:,p], l2) b_vecs[:,p+nocc] = amplitudes_to_vector_ea(b1, b2) e_vecs[:,p+nocc] = amplitudes_to_vector_ea(e1, e2) # Now, apply {\bar H} to each b part_moms = [np.zeros((nmo, nmo)) for i in range(nmom_max_p+1)] # TODO: Would this work for complex? part_moms[0] = np.dot(e_vecs.T.conj(),b_vecs) part_moms[0] += part_moms[0].conj().T #hole_moms[0] = -2.*np.dot(e_vecs.T.conj(),b_vecs) p_RHS = np.zeros_like(b_vecs) for h_app in range(nmom_max_p): if h_app == 0: for p in range(nmo): p_RHS[:,p] = eaccsd_matvec(b_vecs[:,p], imds, diag, nocc, nmo, partition) else: for p in range(nmo): p_RHS[:,p] = eaccsd_matvec(p_RHS[:,p], imds, diag, nocc, nmo, partition) part_moms[h_app+1] = -np.dot(e_vecs.conj().T,p_RHS) part_moms[h_app+1] += part_moms[h_app+1].conj().T if ao_repr: mo = mycc.mo_coeff part_moms = [lib.einsum('pi,ij,qj->pq', mo, mom, mo.conj()) for mom in part_moms] return part_moms
def dia(gobj, mol, dm0, gauge_orig=None): if isinstance(dm0, numpy.ndarray) and dm0.ndim == 2: # RHF DM return numpy.zeros((3, 3)) dma, dmb = dm0 spindm = dma - dmb effspin = mol.spin * .5 alpha2 = lib.param.ALPHA**2 # FIXME: see JPC, 101, 3388, why? g_so = (lib.param.G_ELECTRON - 1) * 2 # relativistic mass correction (RMC) rmc = -numpy.einsum('ij,ji', mol.intor('int1e_kin'), spindm) rmc *= lib.param.G_ELECTRON / 2 / effspin * alpha2 logger.info(gobj, 'RMC = %s', rmc) # GC(1e) if gauge_orig is not None: mol.set_common_origin(gauge_orig) h11 = 0 for ia in range(mol.natm): mol.set_rinv_origin(mol.atom_coord(ia)) Z = mol.atom_charge(ia) #FIXME: when ECP is enabled if gobj.with_so_eff_charge: Z = koseki_charge(Z) # GC(1e) = 1/4c^2 Z/(2r_N^3) [vec{r}_N dot r sigma dot B - B dot vec{r}_N r dot sigma] # a11part = (B dot) -1/2 frac{\vec{r}_N}{r_N^3} r (dot sigma) if gauge_orig is None: h11 += Z * mol.intor('int1e_giao_a11part', 9) else: h11 += Z * mol.intor('int1e_cg_a11part', 9) trh11 = h11[0] + h11[4] + h11[8] h11[0] -= trh11 h11[4] -= trh11 h11[8] -= trh11 if gauge_orig is None: for ia in range(mol.natm): mol.set_rinv_origin(mol.atom_coord(ia)) Z = mol.atom_charge(ia) #FIXME: when ECP is enabled if gobj.with_so_eff_charge: Z = koseki_charge(Z) h11 += Z * mol.intor('int1e_a01gp', 9) gc1e = numpy.einsum('xij,ji->x', h11, spindm).reshape(3, 3) if 0: # correction of order c^{-2} from MB basis or DPT (JCP,115,7356), does it exist? gc1e += numpy.einsum('ij,ji', mol.intor('int1e_nuc'), spindm) * numpy.eye(3) gc1e *= g_so * (alpha2 / 4) / effspin _write(gobj, gc1e, 'GC(1e)') if gobj.with_sso or gobj.with_soo: gc2e = make_dia_gc2e(gobj, dm0, gauge_orig) _write(gobj, gc2e, 'GC(2e)') else: gc2e = 0 gdia = gc1e + gc2e + rmc * numpy.eye(3) return gdia
def build(self): t0 = (time.clock(), time.time()) lib.logger.TIMER_LEVEL = 3 mol = lib.chkfile.load_mol(self.chkfile) self.mol = mol self.nelectron = self.mol.nelectron self.charge = self.mol.charge self.spin = self.mol.spin self.natm = self.mol.natm self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_occ = lib.chkfile.load(self.chkfile, 'scf/mo_occ') self.n2c = self.mol.nao_2c() self.atm = numpy.asarray(self.mol._atm, dtype=numpy.int32, order='C') self.bas = numpy.asarray(self.mol._bas, dtype=numpy.int32, order='C') self.env = numpy.asarray(self.mol._env, dtype=numpy.double, order='C') self.nbas = self.bas.shape[0] self.ao_loc = self.mol.ao_loc_2c() self.shls_slice = (0, self.nbas) sh0, sh1 = self.shls_slice self.nao = self.ao_loc[sh1] - self.ao_loc[sh0] self.non0tab = numpy.ones((1, self.nbas), dtype=numpy.int8) self.coords = numpy.asarray([(numpy.asarray(atom[1])).tolist() for atom in self.mol._atom]) self.charges = self.mol.atom_charges() nprims, nmo = self.mo_coeff.shape self.nprims = nprims self.nmo = nmo self.cart = mol.cart if (not self.leb): self.npang = self.npphi * self.nptheta nocc = self.mo_occ[abs(self.mo_occ) > self.occdrop] self.nocc = len(nocc) pos = abs(self.mo_occ) > self.occdrop n2c = self.n2c self.mo_coeffL = self.mo_coeff[:n2c, pos] c1 = 0.5 / self.cspeed self.mo_coeffS = self.mo_coeff[n2c:, n2c:n2c + self.nocc] * c1 if (self.ntrial % 2 == 0): self.ntrial += 1 geofac = numpy.power(((self.rmaxsurf - 0.1) / self.rprimer), (1.0 / (self.ntrial - 1.0))) self.rpru = numpy.zeros((self.ntrial)) for i in range(self.ntrial): self.rpru[i] = self.rprimer * numpy.power(geofac, (i + 1) - 1) self.rsurf = numpy.zeros((self.npang, self.ntrial), order='C') self.nlimsurf = numpy.zeros((self.npang), dtype=numpy.int32) if self.verbose >= logger.WARN: self.check_sanity() if self.verbose > logger.NOTE: self.dump_input() if (self.iqudt == 'legendre'): self.iqudt = 1 if (self.leb): self.grids = grid.lebgrid(self.npang) else: self.grids = grid.anggrid(self.iqudt, self.nptheta, self.npphi) self.xyzrho = numpy.zeros((self.natm, 3)) t = time.time() for i in range(self.natm): self.xyzrho[i], gradmod = gradrho(self, self.coords[i] + 0.1, self.step) if (gradmod > 1e-4): if (self.charges[i] > 2.0): logger.info(self, 'Good rho position %.6f %.6f %.6f', *self.xyzrho[i]) else: raise RuntimeError('Failed finding nucleus:', *self.xyzrho[i]) else: logger.info(self, 'Check rho position %.6f %.6f %.6f', *self.xyzrho[i]) logger.info(self, 'Setting xyzrho for atom to imput coords') self.xyzrho[i] = self.coords[i] self.xnuc = numpy.asarray(self.xyzrho[self.inuc]) logger.info(self, 'Time finding nucleus %.3f (sec)' % (time.time() - t)) if (self.backend == 'rkck'): backend = 1 elif (self.backend == 'rkdp'): backend = 2 else: raise NotImplementedError( 'Only rkck or rkdp ODE solver yet available') ct_ = numpy.asarray(self.grids[:, 0], order='C') st_ = numpy.asarray(self.grids[:, 1], order='C') cp_ = numpy.asarray(self.grids[:, 2], order='C') sp_ = numpy.asarray(self.grids[:, 3], order='C') t = time.time() feval = 'surf_driver4c' drv = getattr(libaim, feval) with lib.with_omp_threads(self.nthreads): drv(ctypes.c_int(self.inuc), self.xyzrho.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.npang), ct_.ctypes.data_as(ctypes.c_void_p), st_.ctypes.data_as(ctypes.c_void_p), cp_.ctypes.data_as(ctypes.c_void_p), sp_.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.ntrial), self.rpru.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.epsiscp), ctypes.c_double(self.epsroot), ctypes.c_double(self.rmaxsurf), ctypes.c_int(backend), ctypes.c_double(self.epsilon), ctypes.c_double(self.step), ctypes.c_int(self.mstep), ctypes.c_int(self.natm), self.coords.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.cart), ctypes.c_int(self.nocc), ctypes.c_int(self.nprims), self.atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nbas), self.bas.ctypes.data_as(ctypes.c_void_p), self.env.ctypes.data_as(ctypes.c_void_p), self.ao_loc.ctypes.data_as(ctypes.c_void_p), self.mo_coeffL.ctypes.data_as(ctypes.c_void_p), self.mo_coeffS.ctypes.data_as(ctypes.c_void_p), self.nlimsurf.ctypes.data_as(ctypes.c_void_p), self.rsurf.ctypes.data_as(ctypes.c_void_p)) logger.info(self, 'Time finding surface %.3f (sec)' % (time.time() - t)) #print rhograd(self,[0,0,0]) #print rhograd2(self,[0,0,0]) self.rmin = 1000.0 self.rmax = 0.0 for i in range(self.npang): nsurf = int(self.nlimsurf[i]) self.rmin = numpy.minimum(self.rmin, self.rsurf[i, 0]) self.rmax = numpy.maximum(self.rmax, self.rsurf[i, nsurf - 1]) logger.info(self, 'Rmin for surface %.6f', self.rmin) logger.info(self, 'Rmax for surface %.6f', self.rmax) logger.info(self, 'Write HDF5 surface file') atom_dic = { 'inuc': self.inuc, 'xnuc': self.xnuc, 'xyzrho': self.xyzrho, 'coords': self.grids, 'npang': self.npang, 'ntrial': self.ntrial, 'rmin': self.rmin, 'rmax': self.rmax, 'nlimsurf': self.nlimsurf, 'rsurf': self.rsurf } lib.chkfile.save(self.surfile, 'atom' + str(self.inuc), atom_dic) logger.info(self, 'Surface of atom %d saved', self.inuc) logger.timer(self, 'BaderSurf build', *t0) return self
def eaccsd(self, nroots=1, left=False, koopmans=False, guess=None, partition=None): '''Calculate (N+1)-electron charged excitations via EA-EOM-CCSD. Kwargs: See ipccd() ''' cput0 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) size = self.nea() nroots = min(nroots, size) if partition: partition = partition.lower() assert partition in ['mp', 'full'] self.ea_partition = partition if partition == 'full': self._eaccsd_diag_matrix2 = self.vector_to_amplitudes_ea( self.eaccsd_diag())[1] adiag = self.eaccsd_diag() user_guess = False if guess: user_guess = True assert len(guess) == nroots for g in guess: assert g.size == size else: guess = [] if koopmans: for n in range(nroots): g = np.zeros(size) g[n] = 1.0 guess.append(g) else: idx = adiag.argsort()[:nroots] for i in idx: g = np.zeros(size) g[i] = 1.0 guess.append(g) def precond(r, e0, x0): return r / (e0 - adiag + 1e-12) if left: matvec = self.leaccsd_matvec else: matvec = self.eaccsd_matvec eig = linalg_helper.eig if user_guess or koopmans: def pickeig(w, v, nr, envs): x0 = linalg_helper._gen_x0(envs['v'], envs['xs']) idx = np.argmax(np.abs( np.dot(np.array(guess).conj(), np.array(x0).T)), axis=1) return w[idx].real, v[:, idx].real, idx eea, evecs = eig(matvec, guess, precond, pick=pickeig, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) else: eea, evecs = eig(matvec, guess, precond, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) self.eea = eea.real if nroots == 1: eea, evecs = [self.eea], [evecs] nvir = self.nmo - self.nocc for n, en, vn in zip(range(nroots), eea, evecs): logger.info(self, 'EA root %d E = %.16g qpwt = %0.6g', n, en, np.linalg.norm(vn[:nvir])**2) log.timer('EA-CCSD', *cput0) if nroots == 1: return eea[0], evecs[0] else: return eea, evecs
def dump_input(self): if self.verbose < logger.INFO: return self logger.info(self, '') logger.info(self, '******** %s flags ********', self.__class__) logger.info(self, '* General Info') logger.info(self, 'Date %s' % time.ctime()) logger.info(self, 'Python %s' % sys.version) logger.info(self, 'Numpy %s' % numpy.__version__) logger.info(self, 'Number of threads %d' % self.nthreads) logger.info(self, 'Verbose level %d' % self.verbose) logger.info(self, 'Scratch dir %s' % self.scratch) logger.info(self, 'Input data file %s' % self.chkfile) logger.info(self, 'Max_memory %d MB (current use %d MB)', self.max_memory, lib.current_memory()[0]) logger.info(self, '* Mol Info') logger.info(self, 'Speed light value %f' % self.cspeed) logger.info(self, 'Num atoms %d' % self.natm) logger.info(self, 'Num electrons %d' % self.nelectron) logger.info(self, 'Total charge %d' % self.charge) logger.info(self, 'Spin %d ' % self.spin) logger.info(self, 'Atom Coordinates (Bohr)') for i in range(self.natm): logger.info( self, 'Nuclei %d with charge %d position : %.6f %.6f %.6f', i, self.charges[i], *self.coords[i]) logger.info(self, '* Basis Info') logger.info(self, 'Is cartesian %s' % self.cart) logger.info(self, 'Number of molecular orbitals %d' % self.nmo) logger.info(self, 'Orbital EPS occ criterion %e' % self.occdrop) logger.info(self, 'Number of occupied molecular orbitals %d' % self.nocc) logger.info(self, 'Number of molecular primitives %d' % self.nprims) logger.debug(self, 'Occs : %s' % self.mo_occ) logger.info(self, '* Surface Info') if (self.leb): logger.info(self, 'Lebedev quadrature') else: logger.info(self, 'Theta quadrature %s' % self.iqudt) logger.info(self, 'Phi is always trapezoidal') logger.info( self, 'N(theta,phi) points %d %d' % (self.nptheta, self.npphi)) logger.info(self, 'Npang points %d' % self.npang) logger.info(self, 'Surface file %s' % self.surfile) logger.info(self, 'Surface for nuc %d' % self.inuc) logger.info(self, 'Rmaxsurface %f' % self.rmaxsurf) logger.info(self, 'Ntrial %d' % self.ntrial) logger.info(self, 'Rprimer %f' % self.rprimer) logger.debug(self, 'Rpru : %s' % self.rpru) logger.info(self, 'Epsiscp %f' % self.epsiscp) logger.info(self, 'Epsroot %e' % self.epsroot) logger.info(self, 'ODE solver %s' % self.backend) logger.info(self, 'ODE tool %e' % self.epsilon) logger.info(self, 'Max steps in ODE solver %d' % self.mstep) logger.info(self, '') return self
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpts=None, kpts_band=None): """ Coulomb + XC functional + Hubbard U terms. .. note:: This is a replica of pyscf.dft.rks.get_veff with kpts added. This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: Veff : (nkpts, nao, nao) or (*, nkpts, nao, nao) ndarray Veff = J + Vxc + V_U. """ if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpts is None: kpts = ks.kpts # J + V_xc vxc = krks.get_veff(ks, cell=cell, dm=dm, dm_last=dm_last, vhf_last=vhf_last, hermi=hermi, kpts=kpts, kpts_band=kpts_band) # V_U C_ao_lo = ks.C_ao_lo ovlp = ks.get_ovlp() nkpts = len(kpts) nlo = C_ao_lo.shape[-1] rdm1_lo = np.zeros((nkpts, nlo, nlo), dtype=np.complex128) for k in range(nkpts): C_inv = np.dot(C_ao_lo[k].conj().T, ovlp[k]) rdm1_lo[k] = mdot(C_inv, dm[k], C_inv.conj().T) E_U = 0.0 weight = 1.0 / nkpts logger.info(ks, "-" * 79) with np.printoptions(precision=5, suppress=True, linewidth=1000): for idx, val, lab in zip(ks.U_idx, ks.U_val, ks.U_lab): lab_string = " " for l in lab: lab_string += "%9s" % (l.split()[-1]) lab_sp = lab[0].split() logger.info(ks, "local rdm1 of atom %s: ", " ".join(lab_sp[:2]) + " " + lab_sp[2][:2]) U_mesh = np.ix_(idx, idx) P_loc = 0.0 for k in range(nkpts): S_k = ovlp[k] C_k = C_ao_lo[k][:, idx] P_k = rdm1_lo[k][U_mesh] SC = np.dot(S_k, C_k) vxc[k] += mdot(SC, (np.eye(P_k.shape[-1]) - P_k) * (val * 0.5), SC.conj().T).astype(vxc[k].dtype, copy=False) E_U += (val * 0.5) * (P_k.trace() - np.dot(P_k, P_k).trace() * 0.5) P_loc += P_k P_loc = P_loc.real / nkpts logger.info(ks, "%s\n%s", lab_string, P_loc) logger.info(ks, "-" * 79) E_U *= weight if E_U.real < 0.0 and all(np.asarray(ks.U_val) > 0): logger.warn(ks, "E_U (%s) is negative...", E_U.real) vxc = lib.tag_array(vxc, E_U=E_U) return vxc
def dump_flags(self, verbose=None): mol_hf.SCF.dump_flags(self, verbose) logger.info(self, '\n') logger.info(self, '******** PBC SCF flags ********') logger.info(self, 'N kpts = %d', len(self.kpts)) logger.debug(self, 'kpts = %s', self.kpts) logger.info(self, 'Exchange divergence treatment (exxdiv) = %s', self.exxdiv) #if self.exxdiv == 'vcut_ws': # if self.exx_built is False: # self.precompute_exx() # logger.info(self, 'WS alpha = %s', self.exx_alpha) cell = self.cell if ((cell.dimension >= 2 and cell.low_dim_ft_type != 'inf_vacuum') and isinstance(self.exxdiv, str) and self.exxdiv.lower() == 'ewald'): madelung = tools.pbc.madelung(cell, [self.kpts]) logger.info(self, ' madelung (= occupied orbital energy shift) = %s', madelung) nkpts = len(self.kpts) # FIXME: consider the fractional num_electron or not? This maybe # relates to the charged system. nelectron = float(self.cell.tot_electrons(nkpts)) / nkpts logger.info( self, ' Total energy shift due to Ewald probe charge' ' = -1/2 * Nelec*madelung = %.12g', madelung * nelectron * -.5) logger.info(self, 'DF object = %s', self.with_df) if not getattr(self.with_df, 'build', None): # .dump_flags() is called in pbc.df.build function self.with_df.dump_flags(verbose) return self