def kernel(self, h1e, eri, norb, nelec, ci0=None, **kwargs): if self.verbose > logger.QUIET: pyscf.gto.mole.check_sanity(self, self._keys, self.stdout) wfnsym = _id_wfnsym(self, norb, nelec, self.wfnsym) if 'verbose' in kwargs: if isinstance(kwargs['verbose'], logger.Logger): log = kwargs['verbose'] else: log = logger.Logger(self.stdout, kwargs['verbose']) log.debug('total symmetry = %s', symm.irrep_id2name(self.mol.groupname, wfnsym)) else: logger.debug(self, 'total symmetry = %s', symm.irrep_id2name(self.mol.groupname, wfnsym)) e, c = direct_spin1.kernel_ms1(self, h1e, eri, norb, nelec, ci0, **kwargs) if self.wfnsym is not None: # should I remove the non-symmetric contributions in each # call of contract_2e? if self.nroots > 1: c = [addons.symmetrize_wfn(ci, norb, nelec, self.orbsym, wfnsym) for ci in c] else: c = addons.symmetrize_wfn(c, norb, nelec, self.orbsym, wfnsym) return e, c
def kernel(self, mo_coeff=None, ci0=None, callback=None, _kern=None): if mo_coeff is None: mo_coeff = self.mo_coeff if callback is None: callback = self.callback if _kern is None: _kern = newton_casscf.kernel if self.verbose >= logger.WARN: self.check_sanity() self.dump_flags() log = logger.Logger(self.stdout, self.verbose) mo_coeff = self.mo_coeff = casci_symm.label_symmetry_(self, mo_coeff) if (hasattr(self.fcisolver, 'wfnsym') and self.fcisolver.wfnsym is None and hasattr(self.fcisolver, 'guess_wfnsym')): wfnsym = self.fcisolver.guess_wfnsym(self.ncas, self.nelecas, ci0, verbose=log) wfnsym = symm.irrep_id2name(self.mol.groupname, wfnsym) log.info('Active space CI wfn symmetry = %s', wfnsym) self.converged, self.e_tot, self.e_cas, self.ci, \ self.mo_coeff, self.mo_energy = \ _kern(self, mo_coeff, tol=self.conv_tol, conv_tol_grad=self.conv_tol_grad, ci0=ci0, callback=callback, verbose=self.verbose) log.note('CASSCF energy = %.15g', self.e_tot) self._finalize() return self.e_tot, self.e_cas, self.ci, self.mo_coeff, self.mo_energy
def kernel(self, mo_coeff=None, ci0=None, callback=None, _kern=None): if mo_coeff is None: mo_coeff = self.mo_coeff else: self.mo_coeff = mo_coeff if callback is None: callback = self.callback if _kern is None: _kern = mc1step.kernel if self.verbose >= logger.WARN: self.check_sanity() self.dump_flags() log = logger.Logger(self.stdout, self.verbose) casci_symm.label_symmetry_(self, self.mo_coeff) if (hasattr(self.fcisolver, 'wfnsym') and self.fcisolver.wfnsym is None and hasattr(self.fcisolver, 'guess_wfnsym')): wfnsym = self.fcisolver.guess_wfnsym(self.ncas, self.nelecas, ci0, verbose=log) wfnsym = symm.irrep_id2name(self.mol.groupname, wfnsym) log.info('Active space CI wfn symmetry = %s', wfnsym) self.converged, self.e_tot, self.e_cas, self.ci, \ self.mo_coeff, self.mo_energy = \ _kern(self, mo_coeff, tol=self.conv_tol, conv_tol_grad=self.conv_tol_grad, ci0=ci0, callback=callback, verbose=self.verbose) log.note('CASSCF energy = %.15g', self.e_tot) self._finalize() return self.e_tot, self.e_cas, self.ci, self.mo_coeff, self.mo_energy
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 analyze(mf, verbose=logger.DEBUG, **kwargs): mol = mf.mol if not mol.symmetry: return ghf.analyze(mf, verbose, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff ovlp_ao = mf.get_ovlp() log = logger.new_logger(mf, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) orbsym = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False) wfnsym = 0 noccs = [sum(orbsym[mo_occ>0]==ir) for ir in mol.irrep_id] log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s'*nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d'*nirrep), *noccs) log.note('**** MO energy ****') irname_full = {} for k,ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) dm = mf.make_rdm1(mo_coeff, mo_occ) return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
def analyze(mf, verbose=logger.DEBUG, **kwargs): '''Analyze the given SCF object: print orbital energies, occupancies; print orbital coefficients; Occupancy for each irreps; Mulliken population analysis ''' from pyscf.lo import orth from pyscf.tools import dump_mat mol = mf.mol if not mol.symmetry: return hf.analyze(mf, verbose, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff log = logger.Logger(mf.stdout, verbose) nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s=ovlp_ao, check=False) orbsym = numpy.array(orbsym) wfnsym = 0 noccs = [sum(orbsym[mo_occ > 0] == ir) for ir in mol.irrep_id] log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s' * nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d' * nirrep), *noccs) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k + 1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k + 1, irname_full[j], irorbcnt[j])) log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) dump_mat.dump_rec(mf.stdout, c, label, molabel, start=1, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
def dump_flags(self, verbose=None): direct_spin0.FCISolver.dump_flags(self, verbose) log = logger.new_logger(self, verbose) if isinstance(self.wfnsym, str): log.info('specified CI wfn symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.number)): log.info('specified CI wfn symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym))
def dump_flags(self, verbose=None): if verbose is None: verbose = self.verbose direct_spin0.FCISolver.dump_flags(self, verbose) log = pyscf.lib.logger.Logger(self.stdout, verbose) if isinstance(self.wfnsym, str): log.info('specified CI wfn symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.integer)): log.info('specified CI wfn symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym))
def analyze(self, verbose=logger.DEBUG): from pyscf.tools import dump_mat mo_energy = self.mo_energy mo_occ = self.mo_occ mo_coeff = self.mo_coeff log = logger.Logger(self.stdout, verbose) mol = self.mol nirrep = len(mol.irrep_id) ovlp_ao = self.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s=ovlp_ao) orbsym = numpy.array(orbsym) wfnsym = 0 ndoccs = [] nsoccs = [] for k,ir in enumerate(mol.irrep_id): ndoccs.append(sum(orbsym[mo_occ==2] == ir)) nsoccs.append(sum(orbsym[mo_occ==1] == ir)) if nsoccs[k] % 2: wfnsym ^= ir if mol.groupname in ('Dooh', 'Coov'): log.info('TODO: total symmetry for %s', mol.groupname) else: log.info('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.info('occupancy for each irrep: ' + (' %4s'*nirrep), *mol.irrep_name) log.info('double occ ' + (' %4d'*nirrep), *ndoccs) log.info('single occ ' + (' %4d'*nirrep), *nsoccs) log.info('**** MO energy ****') irname_full = {} for k,ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.info('MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** MO coefficients **') dump_mat.dump_rec(mol.stdout, mo_coeff, label, molabel, start=1) dm = self.make_rdm1(mo_coeff, mo_occ) return self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=verbose)
def dump_flags(self, verbose=None): if verbose is None: verbose = self.verbose direct_spin1.FCISolver.dump_flags(self, verbose) log = logger.Logger(self.stdout, verbose) if isinstance(self.wfnsym, str): log.info('specified CI wfn symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.number)): log.info('specified CI wfn symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym)) return self
def get_init_guess(self, norb, nelec, nroots, hdiag_csf): ''' The existing _get_init_guess function will work in the csf basis if I pass it with na, nb = ncsf, 1. This might change in future PySCF versions though. ...For point-group symmetry, I pass the direct_spin1.py version of _get_init_guess with na, nb = ncsf_sym, 1 and hdiag_csf including only csfs of the right point-group symmetry. This should clean up the symmetry-breaking "noise" in direct_spin0_symm.py! ''' wfnsym = _id_wfnsym(self, norb, nelec, self.orbsym, self.wfnsym) wfnsym_str = symm.irrep_id2name (self.mol.groupname, wfnsym) self.check_mask_cache () idx_sym = self.confsym[self.econf_csf_mask] == wfnsym return get_init_guess (norb, nelec, nroots, hdiag_csf, smult=self.smult, csd_mask=self.csd_mask, wfnsym_str=wfnsym_str, idx_sym=idx_sym)
def analyze(mf, verbose=logger.DEBUG, **kwargs): '''Analyze the given SCF object: print orbital energies, occupancies; print orbital coefficients; Occupancy for each irreps; Mulliken population analysis ''' from pyscf.lo import orth from pyscf.tools import dump_mat mol = mf.mol if not mol.symmetry: return hf.analyze(mf, verbose, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff log = logger.Logger(mf.stdout, verbose) nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s=ovlp_ao, check=False) orbsym = numpy.array(orbsym) wfnsym = 0 noccs = [sum(orbsym[mo_occ>0]==ir) for ir in mol.irrep_id] log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s'*nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d'*nirrep), *noccs) log.note('**** MO energy ****') irname_full = {} for k,ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) dump_mat.dump_rec(mf.stdout, c, label, molabel, start=1, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
def dump_flags(self, verbose=None): if verbose is None: verbose = self.verbose direct_spin1.FCISolver.dump_flags(self, verbose) log = logger.Logger(self.stdout, verbose) if isinstance(self.wfnsym, str): log.info('Input CI wfn symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.number)): log.info('Input CI wfn symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym)) else: log.info('CI wfn symmetry = %s', self.wfnsym) return self
def analyze_wfnsym(tdobj, x_sym, x): '''Guess the wfn symmetry of TDDFT X amplitude''' possible_sym = x_sym[(x > 1e-7) | (x < -1e-7)] if numpy.all(possible_sym == symm.MULTI_IRREPS): if tdobj.wfnsym is None: wfnsym = '???' else: wfnsym = tdobj.wfnsym else: ids = possible_sym[possible_sym != symm.MULTI_IRREPS] ids = numpy.unique(ids) if ids.size == 1: wfnsym = symm.irrep_id2name(tdobj.mol.groupname, ids[0]) else: wfnsym = '???' return wfnsym
def dump_flags(self, verbose=None): direct_spin1.FCISolver.dump_flags(self, verbose) log = logger.new_logger(self, verbose) if isinstance(self.wfnsym, str): log.info('Input CI wfn symmetry = %s', self.wfnsym) elif isinstance(self.wfnsym, (int, numpy.number)): try: log.info('Input CI wfn symmetry = %s', symm.irrep_id2name(self.mol.groupname, self.wfnsym)) except KeyError: raise RuntimeError( 'FCISolver cannot find mwfnsym Id %s in group %s. ' 'This might be caused by the projection from ' 'high-symmetry group to D2h symmetry.' % (self.wfnsym, self.mol.groupname)) else: log.info('CI wfn symmetry = %s', self.wfnsym) return self
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 analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): mol = mf.mol if not mol.symmetry: return ghf.analyze(mf, verbose, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff ovlp_ao = mf.get_ovlp() log = logger.new_logger(mf, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) orbsym = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False) wfnsym = 0 noccs = [sum(orbsym[mo_occ>0]==ir) for ir in mol.irrep_id] log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s'*nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d'*nirrep), *noccs) log.note('**** MO energy ****') irname_full = {} for k,ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k+MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) dm = mf.make_rdm1(mo_coeff, mo_occ) dip = mf.dip_moment(mol, dm, verbose=log) if with_meta_lowdin: pop_and_chg = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_chg = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) return pop_and_chg, dip
def run_FCI(molecule: MolecularData, roots: int): pyscf_mol = molecule._pyscf_data['mol'] pyscf_scf = molecule._pyscf_data['scf'] pyscf_mol.symmetry = True pyscf_mol.build() # label orbital symmetries orbsym = scf.hf_symm.get_orbsym(pyscf_mol, pyscf_scf.mo_coeff) pyscf_mol.symmetry = False # generate FCI solver fci_solver = fci.addons.fix_spin_(fci.FCI(pyscf_mol, pyscf_scf.mo_coeff), shift=0.0, ss=1.0) fci_solver.nroots = roots # execute FCI solver f, d = fci_solver.kernel() fci_e = [] print(' FCI:') # iterate over eigenstates for i, x in enumerate(d): energy = f[i] mult = fci.spin_op.spin_square0(x, molecule.n_orbitals, molecule.n_electrons)[1] eigen_symm = fci.addons.guess_wfnsym(x, molecule.n_orbitals, molecule.n_electrons, orbsym) eigen_symm = symm.irrep_id2name('Coov', eigen_symm) fci_e.append((energy, mult)) print('state {}, E = {}, 2S+1 = {}, IrRep = {} '.format( i, round(energy, 5), round(mult), eigen_symm)) return fci_e
def analyze(self, verbose=logger.DEBUG): from pyscf.lo import orth from pyscf.tools import dump_mat mo_energy = self.mo_energy mo_occ = self.mo_occ mo_coeff = self.mo_coeff log = logger.Logger(self.stdout, verbose) mol = self.mol nirrep = len(mol.irrep_id) ovlp_ao = self.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s=ovlp_ao) orbsym = numpy.array(orbsym) wfnsym = 0 ndoccs = [] nsoccs = [] for k,ir in enumerate(mol.irrep_id): ndoccs.append(sum(orbsym[mo_occ==2] == ir)) nsoccs.append(sum(orbsym[mo_occ==1] == ir)) if nsoccs[k] % 2: wfnsym ^= ir if mol.groupname in ('Dooh', 'Coov'): log.info('TODO: total symmetry for %s', mol.groupname) else: log.info('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.info('occupancy for each irrep: ' + (' %4s'*nirrep), *mol.irrep_name) log.info('double occ ' + (' %4d'*nirrep), *ndoccs) log.info('single occ ' + (' %4d'*nirrep), *nsoccs) log.info('**** MO energy ****') irname_full = {} for k,ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} if self._focka_ao is None: for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) else: mo_ea = numpy.einsum('ik,ik->k', mo_coeff, self._focka_ao.dot(mo_coeff)) mo_eb = numpy.einsum('ik,ik->k', mo_coeff, self._fockb_ao.dot(mo_coeff)) log.note(' Roothaan | alpha | beta') for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k]) if verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) dump_mat.dump_rec(self.stdout, c, label, molabel, start=1) dm = self.make_rdm1(mo_coeff, mo_occ) return self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=verbose)
def __init__(self, mol_or_hdf5, c=None, network=None, verbose=None): '''Initializing the T3NS calculation. Args: mol_or_hdf5: An instance of :class:`Mole` from PySCF or a string to a path of the hdf5 file. In this case c and network should be left as defaults. c: The orbital coefficients. The default are the RHF orbitals. network: Network of the tensor network. This can be the string 'DMRG' for a linear chain or 'T3NS' for a T3NS that is radially extended (i.e. the maximal distance between two sites is minimal). An instance of :class:`Network` is also accepted for custom networks or a path to a network file. Default is 'T3NS' if Mole instance was passed, else None. ''' from pyscf import symm if isinstance(mol_or_hdf5, pyscf.gto.Mole): # Initialize with RHF mol = mol_or_hdf5 if network is None: network = 'T3NS' if verbose is None: self.verbose = mol.verbose self.mol = mol # if no orbital coefficients are given, use RHF orbitals if c is None: myhf = pyscf.scf.RHF(mol) myhf.verbose = self.verbose myhf.kernel() c = myhf.mo_coeff self._c = c self._mol = mol self._eri = pyscf.ao2mo.kernel(mol, c) self.symmetries = ['Z2', 'U1', 'SU2'] self.target = [int(mol.nelectron % 2), mol.nelectron, mol.spin] try: irrep_ids = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, c) newsym = mol.groupname if mol.groupname == 'Dooh' or mol.groupname == 'Coov': newsym = 'D2h' if mol.groupname else 'C2v' if self.verbose > 1: print(f'Changed point group from {mol.groupname} to ' f'{newsym}') # mod 10 needed for translation Coov and Dooh # See https://sunqm.github.io/pyscf/symm.html self._pg_irrep = [ symm.irrep_id2name(newsym, int(ii % 10)) for ii in irrep_ids ] self.symmetries.append(newsym) self.target.append(symm.irrep_id2name(newsym, 0)) except (ValueError, TypeError): self._pg_irrep = None if isinstance(network, netw.Network): self._netw = network elif network == 'DMRG' or network == 'T3NS': isDMRG = network == 'DMRG' self._netw = netw.Network(c.shape[1], isDMRG=isDMRG) # exchange matrix # Kij = numpy.zeros((c.shape[1],) * 2) # trids = numpy.tril_indices(c.shape[1], 0) # for el, r, c in zip(self._eri.diagonal(), trids[0], trids[1]): # Kij[r, c] = el # Kij[c, r] = el # cost = self._netw.optimize(Kij) # if self.verbose >= 2: # print(f'Optimization Exchange-cost: {cost}') elif isinstance(network, str): self._netw = netw.Network() self._netw.readnetworkfile(network) else: raise ValueError(f'{network} is invalid for network') self._netw.pass_network() elif isinstance(mol_or_hdf5, str): # h5path = mol_or_hdf5 if verbose is None: self.verbose = 1 if c is not None or network is not None: raise ValueError( 'A hdf5 file does not expect a defined c or network') raise ValueError('Need to implement hdf5 readin still') else: raise ValueError( 'Expects a Mole instance or a path to a hdf5 file')
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 analyze(tdobj, verbose=None): log = logger.new_logger(tdobj, verbose) mol = tdobj.mol mo_coeff = tdobj._scf.mo_coeff mo_occ = tdobj._scf.mo_occ nocc = numpy.count_nonzero(mo_occ == 2) e_ev = numpy.asarray(tdobj.e) * nist.HARTREE2EV e_wn = numpy.asarray(tdobj.e) * nist.HARTREE2WAVENUMBER wave_length = 1e11/e_wn if tdobj.singlet: log.note('\n** Singlet excitation energies and oscillator strengths **') else: log.note('\n** Triplet excitation energies and oscillator strengths **') if mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 x_sym = (orbsym[mo_occ==0,None] ^ orbsym[mo_occ==2]).ravel() else: x_sym = None f_oscillator = tdobj.oscillator_strength() for i, ei in enumerate(tdobj.e): x, y = tdobj.xy[i] if x_sym is None: log.note('Excited State %3d: %12.5f eV %9.2f nm f=%.4f', i+1, e_ev[i], wave_length[i], f_oscillator[i]) else: wfnsym_id = x_sym[abs(x).argmax()] wfnsym = symm.irrep_id2name(mol.groupname, wfnsym_id) log.note('Excited State %3d: %4s %12.5f eV %9.2f nm f=%.4f', i+1, wfnsym, e_ev[i], wave_length[i], f_oscillator[i]) if log.verbose >= logger.INFO: o_idx, v_idx = numpy.where(abs(x) > 0.1) for o, v in zip(o_idx, v_idx): log.info(' %4d -> %-4d %12.5f', o+MO_BASE, v+MO_BASE+nocc, x[o,v]) if log.verbose >= logger.INFO: log.info('\n** Transition electric dipole moments (AU) **') log.info('state X Y Z Dip. S. Osc.') trans_dip = tdobj.transition_dipole() for i, ei in enumerate(tdobj.e): dip = trans_dip[i] log.info('%3d %11.4f %11.4f %11.4f %11.4f %11.4f', i+1, dip[0], dip[1], dip[2], numpy.dot(dip, dip), f_oscillator[i]) log.info('\n** Transition velocity dipole moments (imaginary part AU) **') log.info('state X Y Z Dip. S. Osc.') trans_v = tdobj.transition_velocity_dipole() f_v = tdobj.oscillator_strength(gauge='velocity', order=0) for i, ei in enumerate(tdobj.e): v = trans_v[i] log.info('%3d %11.4f %11.4f %11.4f %11.4f %11.4f', i+1, v[0], v[1], v[2], numpy.dot(v, v), f_v[i]) log.info('\n** Transition magnetic dipole moments (AU) **') log.info('state X Y Z') trans_m = tdobj.transition_magnetic_dipole() for i, ei in enumerate(tdobj.e): m = trans_m[i] log.info('%3d %11.4f %11.4f %11.4f', i+1, m[0], m[1], m[2]) return tdobj
def analyze(self, verbose=logger.DEBUG): from pyscf.lo import orth from pyscf.tools import dump_mat mo_energy = self.mo_energy mo_occ = self.mo_occ mo_coeff = self.mo_coeff log = logger.Logger(self.stdout, verbose) mol = self.mol nirrep = len(mol.irrep_id) ovlp_ao = self.get_ovlp() orbsym = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff, s=ovlp_ao) orbsym = numpy.array(orbsym) wfnsym = 0 ndoccs = [] nsoccs = [] for k, ir in enumerate(mol.irrep_id): ndoccs.append(sum(orbsym[mo_occ == 2] == ir)) nsoccs.append(sum(orbsym[mo_occ == 1] == ir)) if nsoccs[k] % 2: wfnsym ^= ir if mol.groupname in ('Dooh', 'Coov'): log.info('TODO: total symmetry for %s', mol.groupname) else: log.info('total symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.info('occupancy for each irrep: ' + (' %4s' * nirrep), *mol.irrep_name) log.info('double occ ' + (' %4d' * nirrep), *ndoccs) log.info('single occ ' + (' %4d' * nirrep), *nsoccs) log.info('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} if self._focka_ao is None: for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g', k + 1, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) else: mo_ea = numpy.einsum('ik,ik->k', mo_coeff, self._focka_ao.dot(mo_coeff)) mo_eb = numpy.einsum('ik,ik->k', mo_coeff, self._fockb_ao.dot(mo_coeff)) log.note( ' Roothaan | alpha | beta' ) for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note( 'MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g', k + 1, irname_full[j], irorbcnt[j], mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k]) if verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k + 1, irname_full[j], irorbcnt[j])) log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) dump_mat.dump_rec(self.stdout, c, label, molabel, start=1) dm = self.make_rdm1(mo_coeff, mo_occ) return self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=verbose)
def analyze(self, verbose=None, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): if verbose is None: verbose = self.verbose from pyscf.lo import orth from pyscf.tools import dump_mat if not self.mol.symmetry: return rohf.ROHF.analyze(self, verbose, with_meta_lowdin, **kwargs) mol = self.mol mo_energy = self.mo_energy mo_occ = self.mo_occ mo_coeff = self.mo_coeff ovlp_ao = self.get_ovlp() log = logger.new_logger(self, verbose) if log.verbose >= logger.NOTE: self.dump_scf_summary(log) nirrep = len(mol.irrep_id) orbsym = self.get_orbsym(mo_coeff, self.get_ovlp()) irreps = numpy.asarray(mol.irrep_id) ndoccs = numpy.count_nonzero(irreps[:, None] == orbsym[mo_occ == 2], axis=1) nsoccs = numpy.count_nonzero(irreps[:, None] == orbsym[mo_occ == 1], axis=1) wfnsym = 0 # wfn symmetry is determined by the odd number of electrons in each irrep for k in numpy.where(nsoccs % 2 == 1)[0]: ir_in_d2h = mol.irrep_id[k] % 10 # convert to D2h irreps wfnsym ^= ir_in_d2h if mol.groupname in ('SO3', 'Dooh', 'Coov'): # TODO: check wave function symmetry log.note('Wave-function symmetry = %s', mol.groupname) else: log.note('Wave-function symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s' * nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d' * nirrep), *ndoccs) log.note('single occ ' + (' %4d' * nirrep), *nsoccs) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} if getattr(mo_energy, 'mo_ea', None) is not None: mo_ea = mo_energy.mo_ea mo_eb = mo_energy.mo_eb log.note( ' Roothaan | alpha | beta' ) for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note( 'MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g', k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k]) else: for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g', k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if log.verbose >= logger.DEBUG: label = mol.ao_labels() molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k + MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug( ' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.conj().T, ovlp_ao, mo_coeff)) else: log.debug(' ** MO coefficients (expansion on AOs) **') c = mo_coeff dump_mat.dump_rec(self.stdout, c, label, molabel, start=MO_BASE, **kwargs) dm = self.make_rdm1(mo_coeff, mo_occ) if with_meta_lowdin: pop_and_charge = self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_charge = self.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) dip = self.dip_moment(mol, dm, verbose=log) return pop_and_charge, dip
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): '''Analyze the given SCF object: print orbital energies, occupancies; print orbital coefficients; Occupancy for each irreps; Mulliken population analysis ''' from pyscf.lo import orth from pyscf.tools import dump_mat mol = mf.mol if not mol.symmetry: return hf.analyze(mf, verbose, with_meta_lowdin, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff ovlp_ao = mf.get_ovlp() log = logger.new_logger(mf, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) orbsym = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False) wfnsym = 0 noccs = [sum(orbsym[mo_occ > 0] == ir) for ir in mol.irrep_id] if mol.groupname in ('SO3', 'Dooh', 'Coov'): log.note('TODO: total wave-function symmetry for %s', mol.groupname) else: log.note('Wave-function symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s' * nirrep), *mol.irrep_name) log.note(' ' + (' %4d' * nirrep), *noccs) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%d (%s #%d), energy= %.15g occ= %g', k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if log.verbose >= logger.DEBUG: label = mol.ao_labels() molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k + MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug(' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) else: log.debug(' ** MO coefficients (expansion on AOs) **') c = mo_coeff dump_mat.dump_rec(mf.stdout, c, label, molabel, start=MO_BASE, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) if with_meta_lowdin: pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) dip = mf.dip_moment(mol, dm, verbose=log) return pop_and_charge, dip
def analyze(mf, verbose=logger.DEBUG): from pyscf.lo import orth from pyscf.tools import dump_mat mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff mol = mf.mol log = pyscf.lib.logger.Logger(mf.stdout, verbose) nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsyma = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff[0], s=ovlp_ao) orbsymb = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff[1], s=ovlp_ao) orbsyma = numpy.array(orbsyma) orbsymb = numpy.array(orbsymb) tot_sym = 0 noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id] noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id] for i, ir in enumerate(mol.irrep_id): if (noccsa[i]+noccsb[i]) % 2: tot_sym ^= ir if mol.groupname in ('Dooh', 'Coov', 'SO3'): log.note('TODO: total symmetry for %s', mol.groupname) else: log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, tot_sym)) log.note('alpha occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsa) log.note('beta occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsb) ss, s = mf.spin_square((mo_coeff[0][:,mo_occ[0]>0], mo_coeff[1][:,mo_occ[1]>0]), ovlp_ao) log.note('multiplicity <S^2> = %.8g 2S+1 = %.8g', ss, s) if verbose >= logger.NOTE: log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k]) irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('beta MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k]) ovlp_ao = mf.get_ovlp() if mf.verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c_inv = numpy.dot(orth_coeff.T, ovlp_ao) dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[0]), label, molabel, start=1) molabel = [] irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **') dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[1]), label, molabel, start=1) dm = mf.make_rdm1(mo_coeff, mo_occ) return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): from pyscf.lo import orth from pyscf.tools import dump_mat mol = mf.mol if not mol.symmetry: return uhf.analyze(mf, verbose, with_meta_lowdin, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff ovlp_ao = mf.get_ovlp() log = logger.new_logger(mf, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsyma, orbsymb = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False) tot_sym = 0 noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id] noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id] for i, ir in enumerate(mol.irrep_id): if (noccsa[i]+noccsb[i]) % 2: tot_sym ^= ir if mol.groupname in ('Dooh', 'Coov', 'SO3'): log.note('TODO: total wave-function symmetry for %s', mol.groupname) else: log.note('Wave-function symmetry = %s', symm.irrep_id2name(mol.groupname, tot_sym)) log.note('alpha occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsa) log.note('beta occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsb) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g', k+MO_BASE, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k]) irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('beta MO #%d (%s #%d), energy= %.15g occ= %g', k+MO_BASE, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k]) if mf.verbose >= logger.DEBUG: label = mol.ao_labels() molabel = [] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c_inv = numpy.dot(orth_coeff.T, ovlp_ao) mo = c_inv.dot(mo_coeff[0]) else: log.debug(' ** alpha MO coefficients (expansion on AOs) **') mo = mo_coeff[0] dump_mat.dump_rec(mf.stdout, mo, label, start=MO_BASE, **kwargs) molabel = [] irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **') mo = c_inv.dot(mo_coeff[1]) else: log.debug(' ** beta MO coefficients (expansion on AOs) **') mo = mo_coeff[1] dump_mat.dump_rec(mol.stdout, mo, label, molabel, start=MO_BASE, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) if with_meta_lowdin: pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) dip = mf.dip_moment(mol, dm, verbose=log) return pop_and_charge, dip
def analyze(mf, verbose=logger.DEBUG, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): from pyscf.lo import orth from pyscf.tools import dump_mat mol = mf.mol if not mol.symmetry: return uhf.analyze(mf, verbose, with_meta_lowdin, **kwargs) mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff ovlp_ao = mf.get_ovlp() log = logger.new_logger(mf, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsyma, orbsymb = get_orbsym(mf.mol, mo_coeff, ovlp_ao, False) tot_sym = 0 noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id] noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id] for i, ir in enumerate(mol.irrep_id): if (noccsa[i]+noccsb[i]) % 2: tot_sym ^= ir if mol.groupname in ('Dooh', 'Coov', 'SO3'): log.note('TODO: total wave-function symmetry for %s', mol.groupname) else: log.note('Wave-function symmetry = %s', symm.irrep_id2name(mol.groupname, tot_sym)) log.note('alpha occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsa) log.note('beta occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsb) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g', k+MO_BASE, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k]) irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('beta MO #%d (%s #%d), energy= %.15g occ= %g', k+MO_BASE, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k]) if mf.verbose >= logger.DEBUG: label = mol.ao_labels() molabel = [] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c_inv = numpy.dot(orth_coeff.conj().T, ovlp_ao) mo = c_inv.dot(mo_coeff[0]) else: log.debug(' ** alpha MO coefficients (expansion on AOs) **') mo = mo_coeff[0] dump_mat.dump_rec(mf.stdout, mo, label, start=MO_BASE, **kwargs) molabel = [] irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **') mo = c_inv.dot(mo_coeff[1]) else: log.debug(' ** beta MO coefficients (expansion on AOs) **') mo = mo_coeff[1] dump_mat.dump_rec(mol.stdout, mo, label, molabel, start=MO_BASE, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) if with_meta_lowdin: pop_and_charge = mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_charge = mf.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) dip = mf.dip_moment(mol, dm, verbose=log) return pop_and_charge, dip
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 label_symmetry_(mc, mo_coeff, ci0=None): log = logger.Logger(mc.stdout, mc.verbose) #irrep_name = mc.mol.irrep_name irrep_name = mc.mol.irrep_id s = mc._scf.get_ovlp() ncore = mc.ncore nocc = ncore + mc.ncas try: orbsym = scf.hf_symm.get_orbsym(mc._scf.mol, mo_coeff, s, True) except ValueError: log.warn('mc1step_symm symmetrizes input orbitals') mo_cor = symm.symmetrize_space(mc.mol, mo_coeff[:, :ncore], s=s, check=False) mo_act = symm.symmetrize_space(mc.mol, mo_coeff[:,ncore:nocc], s=s, check=False) mo_vir = symm.symmetrize_space(mc.mol, mo_coeff[:,nocc: ], s=s, check=False) mo_coeff = numpy.hstack((mo_cor,mo_act,mo_vir)) orbsym = symm.label_orb_symm(mc.mol, irrep_name, mc.mol.symm_orb, mo_coeff, s=s) mo_coeff_with_orbsym = lib.tag_array(mo_coeff, orbsym=orbsym) active_orbsym = getattr(mc.fcisolver, 'orbsym', []) if (not getattr(active_orbsym, '__len__', None)) or len(active_orbsym) == 0: mc.fcisolver.orbsym = orbsym[ncore:nocc] log.debug('Active space irreps %s', str(mc.fcisolver.orbsym)) wfnsym = 0 if getattr(mc.fcisolver, 'wfnsym', None) is not None: wfnsym = mc.fcisolver.wfnsym elif ci0 is None: # Guess wfnsym based on HF determinant. mo_coeff may not be HF # canonical orbitals. Some checks are needed to ensure that mo_coeff # are derived from the symmetry adapted SCF calculations. if mo_coeff is mc._scf.mo_coeff: wfnsym = 0 for ir in orbsym[mc._scf.mo_occ == 1]: wfnsym ^= ir mc.fcisolver.wfnsym = wfnsym log.debug('Set CASCI wfnsym %s based on HF determinant', wfnsym) elif getattr(mo_coeff, 'orbsym', None) is not None: # It may be reordered SCF orbitals cas_orb = mo_coeff[:,ncore:nocc] s = reduce(numpy.dot, (cas_orb.T, mc._scf.get_ovlp(), mc._scf.mo_coeff)) if numpy.all(numpy.max(s, axis=1) > 1-1e-9): idx = numpy.argmax(s, axis=1) cas_orbsym = orbsym[ncore:nocc] cas_occ = mc._scf.mo_occ[idx] wfnsym = 0 for ir in cas_orbsym[cas_occ == 1]: wfnsym ^= ir mc.fcisolver.wfnsym = wfnsym log.debug('Active space are constructed from canonical SCF ' 'orbitals %s', idx) log.debug('Set CASCI wfnsym %s based on HF determinant', wfnsym) elif getattr(mc.fcisolver, 'guess_wfnsym', None): wfnsym = mc.fcisolver.guess_wfnsym(mc.ncas, mc.nelecas, ci0, verbose=log) log.debug('CASCI wfnsym %s (based on CI initial guess)', wfnsym) if isinstance(wfnsym, (int, numpy.integer)): wfnsym = symm.irrep_id2name(mc.mol.groupname, wfnsym) log.info('Active space CI wfn symmetry = %s', wfnsym) return mo_coeff_with_orbsym
def label_symmetry_(mc, mo_coeff, ci0=None): log = logger.Logger(mc.stdout, mc.verbose) #irrep_name = mc.mol.irrep_name irrep_name = mc.mol.irrep_id s = mc._scf.get_ovlp() ncore = mc.ncore nocc = ncore + mc.ncas try: orbsym = scf.hf_symm.get_orbsym(mc._scf.mol, mo_coeff, s, True) except ValueError: log.warn('mc1step_symm symmetrizes input orbitals') mo_cor = symm.symmetrize_space(mc.mol, mo_coeff[:, :ncore], s=s, check=False) mo_act = symm.symmetrize_space(mc.mol, mo_coeff[:, ncore:nocc], s=s, check=False) mo_vir = symm.symmetrize_space(mc.mol, mo_coeff[:, nocc:], s=s, check=False) mo_coeff = numpy.hstack((mo_cor, mo_act, mo_vir)) orbsym = symm.label_orb_symm(mc.mol, irrep_name, mc.mol.symm_orb, mo_coeff, s=s) mo_coeff_with_orbsym = lib.tag_array(mo_coeff, orbsym=orbsym) active_orbsym = getattr(mc.fcisolver, 'orbsym', []) if (not getattr(active_orbsym, '__len__', None)) or len(active_orbsym) == 0: mc.fcisolver.orbsym = orbsym[ncore:nocc] log.info( 'Symmetries of active orbitals: %s', ' '.join([ symm.irrep_id2name(mc.mol.groupname, irrep) for irrep in mc.fcisolver.orbsym ])) wfnsym = 0 if getattr(mc.fcisolver, 'wfnsym', None) is not None: wfnsym = mc.fcisolver.wfnsym log.debug('Use fcisolver.wfnsym %s', wfnsym) elif ci0 is None: # Guess wfnsym based on HF determinant. mo_coeff may not be HF # canonical orbitals. Some checks are needed to ensure that mo_coeff # are derived from the symmetry adapted SCF calculations. if mo_coeff is mc._scf.mo_coeff: wfnsym = 0 orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps for ir in orbsym_in_d2h[mc._scf.mo_occ == 1]: wfnsym ^= ir mc.fcisolver.wfnsym = wfnsym log.debug('Set CASCI wfnsym %s based on HF determinant', wfnsym) elif getattr(mo_coeff, 'orbsym', None) is not None: # It may be reordered SCF orbitals cas_orb = mo_coeff[:, ncore:nocc] s = reduce( numpy.dot, (cas_orb.conj().T, mc._scf.get_ovlp(), mc._scf.mo_coeff)) if numpy.all(numpy.max(s, axis=1) > 1 - 1e-9): idx = numpy.argmax(s, axis=1) cas_orbsym_in_d2h = numpy.asarray(orbsym[ncore:nocc]) % 10 cas_occ = mc._scf.mo_occ[idx] wfnsym = 0 for ir in cas_orbsym_in_d2h[cas_occ == 1]: wfnsym ^= ir mc.fcisolver.wfnsym = wfnsym log.debug( 'Active space are constructed from canonical SCF ' 'orbitals %s', idx) log.debug('Set CASCI wfnsym %s based on HF determinant', wfnsym) elif getattr(mc.fcisolver, 'guess_wfnsym', None): wfnsym = mc.fcisolver.guess_wfnsym(mc.ncas, mc.nelecas, ci0, verbose=log) log.debug('CASCI wfnsym %s (based on CI initial guess)', wfnsym) if isinstance(wfnsym, (int, numpy.integer)): try: wfnsym = symm.irrep_id2name(mc.mol.groupname, wfnsym) except KeyError: log.warn( 'mwfnsym Id %s not found in group %s. This might be caused by ' 'the projection from high-symmetry group to D2h symmetry.', wfnsym, mc.mol.groupname) log.info('Active space CI wfn symmetry = %s', wfnsym) return mo_coeff_with_orbsym
def analyze(self, verbose=None, with_meta_lowdin=WITH_META_LOWDIN, **kwargs): if verbose is None: verbose = self.verbose from pyscf.lo import orth from pyscf.tools import dump_mat if not self.mol.symmetry: return rohf.ROHF.analyze(self, verbose, with_meta_lowdin, **kwargs) mol = self.mol mo_energy = self.mo_energy mo_occ = self.mo_occ mo_coeff = self.mo_coeff ovlp_ao = self.get_ovlp() log = logger.new_logger(self, verbose) if log.verbose >= logger.NOTE: nirrep = len(mol.irrep_id) orbsym = get_orbsym(self.mol, mo_coeff) wfnsym = 0 ndoccs = [] nsoccs = [] for k, ir in enumerate(mol.irrep_id): ndoccs.append(sum(orbsym[mo_occ == 2] == ir)) nsoccs.append(sum(orbsym[mo_occ == 1] == ir)) if nsoccs[k] % 2 == 1: wfnsym ^= ir if mol.groupname in ('SO3', 'Dooh', 'Coov'): log.note('TODO: total wave-function symmetry for %s', mol.groupname) else: log.note('Wave-function symmetry = %s', symm.irrep_id2name(mol.groupname, wfnsym)) log.note('occupancy for each irrep: ' + (' %4s' * nirrep), *mol.irrep_name) log.note('double occ ' + (' %4d' * nirrep), *ndoccs) log.note('single occ ' + (' %4d' * nirrep), *nsoccs) log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} if hasattr(mo_energy, 'mo_ea'): mo_ea = mo_energy.mo_ea mo_eb = mo_energy.mo_eb log.note( ' Roothaan | alpha | beta' ) for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note( 'MO #%-4d(%-3s #%-2d) energy= %-18.15g | %-18.15g | %-18.15g occ= %g', k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_ea[k], mo_eb[k], mo_occ[k]) else: for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('MO #%-3d (%s #%-2d), energy= %-18.15g occ= %g', k + MO_BASE, irname_full[j], irorbcnt[j], mo_energy[k], mo_occ[k]) if log.verbose >= logger.DEBUG: label = mol.ao_labels() molabel = [] irorbcnt = {} for k, j in enumerate(orbsym): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k + MO_BASE, irname_full[j], irorbcnt[j])) if with_meta_lowdin: log.debug( ' ** MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c = reduce(numpy.dot, (orth_coeff.T, ovlp_ao, mo_coeff)) else: log.debug(' ** MO coefficients (expansion on AOs) **') c = mo_coeff dump_mat.dump_rec(self.stdout, c, label, molabel, start=MO_BASE, **kwargs) dm = self.make_rdm1(mo_coeff, mo_occ) if with_meta_lowdin: pop_and_charge = self.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log) else: pop_and_charge = self.mulliken_pop(mol, dm, s=ovlp_ao, verbose=log) dip = self.dip_moment(mol, dm, verbose=log) return pop_and_charge, dip
def analyze(mf, verbose=logger.DEBUG, **kwargs): from pyscf.lo import orth from pyscf.tools import dump_mat mo_energy = mf.mo_energy mo_occ = mf.mo_occ mo_coeff = mf.mo_coeff mol = mf.mol log = logger.Logger(mf.stdout, verbose) nirrep = len(mol.irrep_id) ovlp_ao = mf.get_ovlp() orbsyma = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff[0], s=ovlp_ao) orbsymb = symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mo_coeff[1], s=ovlp_ao) orbsyma = numpy.array(orbsyma) orbsymb = numpy.array(orbsymb) tot_sym = 0 noccsa = [sum(orbsyma[mo_occ[0]>0]==ir) for ir in mol.irrep_id] noccsb = [sum(orbsymb[mo_occ[1]>0]==ir) for ir in mol.irrep_id] for i, ir in enumerate(mol.irrep_id): if (noccsa[i]+noccsb[i]) % 2: tot_sym ^= ir if mol.groupname in ('Dooh', 'Coov', 'SO3'): log.note('TODO: total symmetry for %s', mol.groupname) else: log.note('total symmetry = %s', symm.irrep_id2name(mol.groupname, tot_sym)) log.note('alpha occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsa) log.note('beta occupancy for each irrep: '+(' %4s'*nirrep), *mol.irrep_name) log.note(' '+(' %4d'*nirrep), *noccsb) ss, s = mf.spin_square((mo_coeff[0][:,mo_occ[0]>0], mo_coeff[1][:,mo_occ[1]>0]), ovlp_ao) log.note('multiplicity <S^2> = %.8g 2S+1 = %.8g', ss, s) if verbose >= logger.NOTE: log.note('**** MO energy ****') irname_full = {} for k, ir in enumerate(mol.irrep_id): irname_full[ir] = mol.irrep_name[k] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('alpha MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[0][k], mo_occ[0][k]) irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 log.note('beta MO #%d (%s #%d), energy= %.15g occ= %g', k+1, irname_full[j], irorbcnt[j], mo_energy[1][k], mo_occ[1][k]) ovlp_ao = mf.get_ovlp() if mf.verbose >= logger.DEBUG: label = mol.spheric_labels(True) molabel = [] irorbcnt = {} for k, j in enumerate(orbsyma): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** alpha MO coefficients (expansion on meta-Lowdin AOs) **') orth_coeff = orth.orth_ao(mol, 'meta_lowdin', s=ovlp_ao) c_inv = numpy.dot(orth_coeff.T, ovlp_ao) dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[0]), label, molabel, start=1, **kwargs) molabel = [] irorbcnt = {} for k, j in enumerate(orbsymb): if j in irorbcnt: irorbcnt[j] += 1 else: irorbcnt[j] = 1 molabel.append('#%-d(%s #%d)' % (k+1, irname_full[j], irorbcnt[j])) log.debug(' ** beta MO coefficients (expansion on meta-Lowdin AOs) **') dump_mat.dump_rec(mol.stdout, c_inv.dot(mo_coeff[1]), label, molabel, start=1, **kwargs) dm = mf.make_rdm1(mo_coeff, mo_occ) return mf.mulliken_meta(mol, dm, s=ovlp_ao, verbose=log)
def lassi(las, mo_coeff=None, ci=None, veff_c=None, h2eff_sub=None, orbsym=None, opt=1): ''' Diagonalize the state-interaction matrix of LASSCF ''' if mo_coeff is None: mo_coeff = las.mo_coeff if ci is None: ci = las.ci if orbsym is None: orbsym = getattr(las.mo_coeff, 'orbsym', None) if orbsym is None and callable(getattr(las, 'label_symmetry_', None)): orbsym = las.label_symmetry_(las.mo_coeff).orbsym if orbsym is not None: orbsym = orbsym[las.ncore:las.ncore + las.ncas] o0_memcheck = op_o0.memcheck(las, ci) if opt == 0 and o0_memcheck == False: raise RuntimeError('Insufficient memory to use o0 LASSI algorithm') # Construct second-quantization Hamiltonian e0, h1, h2 = ham_2q(las, mo_coeff, veff_c=None, h2eff_sub=None) # Symmetry tuple: neleca, nelecb, irrep statesym, s2_states = las_symm_tuple(las) # Loop over symmetry blocks e_roots = np.zeros(las.nroots, dtype=np.float64) s2_roots = np.zeros(las.nroots, dtype=np.float64) si = np.zeros((las.nroots, las.nroots), dtype=np.float64) s2_mat = np.zeros((las.nroots, las.nroots), dtype=np.float64) for rootsym in set(statesym): idx = np.all(np.array(statesym) == rootsym, axis=1) lib.logger.debug( las, 'Diagonalizing LAS state symmetry block (neleca, nelecb, irrep) = {}' .format(rootsym)) if np.count_nonzero(idx) == 1: lib.logger.debug(las, 'Only one state in this symmetry block') e_roots[idx] = las.e_states[idx] - e0 si[np.ix_(idx, idx)] = 1.0 s2_roots[idx] = s2_states[idx] continue wfnsym = rootsym[-1] ci_blk = [[c for c, ix in zip(cr, idx) if ix] for cr in ci] t0 = (time.clock(), time.time()) if (las.verbose > lib.logger.INFO) and (o0_memcheck): ham_ref, s2_ref, ovlp_ref = op_o0.ham(las, h1, h2, ci_blk, idx, orbsym=orbsym, wfnsym=wfnsym) t0 = lib.logger.timer( las, 'LASSI diagonalizer rootsym {} CI algorithm'.format(rootsym), *t0) ham_blk, s2_blk, ovlp_blk = op_o1.ham(las, h1, h2, ci_blk, idx, orbsym=orbsym, wfnsym=wfnsym) t0 = lib.logger.timer( las, 'LASSI diagonalizer rootsym {} TDM algorithm'.format(rootsym), *t0) lib.logger.debug( las, 'LASSI diagonalizer rootsym {}: ham o0-o1 algorithm disagreement = {}' .format(rootsym, linalg.norm(ham_blk - ham_ref))) lib.logger.debug( las, 'LASSI diagonalizer rootsym {}: S2 o0-o1 algorithm disagreement = {}' .format(rootsym, linalg.norm(s2_blk - s2_ref))) lib.logger.debug( las, 'LASSI diagonalizer rootsym {}: ovlp o0-o1 algorithm disagreement = {}' .format(rootsym, linalg.norm(ovlp_blk - ovlp_ref))) errvec = np.concatenate([(ham_blk - ham_ref).ravel(), (s2_blk - s2_ref).ravel(), (ovlp_blk - ovlp_ref).ravel()]) if np.amax(np.abs(errvec)) > 1e-8: raise RuntimeError(( "Congratulations, you have found a bug in either lassi_op_o0 (I really hope not)" " or lassi_op_o1 (much more likely)!\nPlease inspect the last few printed lines of logger output" " for more information.\nError in lassi, max abs: {}; norm: {}" ).format(np.amax(np.abs(errvec)), linalg.norm(errvec))) if opt == 0: ham_blk = ham_ref s2_blk = s2_ref ovlp_blk = ovlp_ref else: if (las.verbose > lib.logger.INFO): lib.logger.debug( las, 'Insufficient memory to test against o0 LASSI algorithm') ham_blk, s2_blk, ovlp_blk = op[opt].ham(las, h1, h2, ci_blk, idx, orbsym=orbsym, wfnsym=wfnsym) t0 = lib.logger.timer( las, 'LASSI diagonalizer rootsym {}'.format(rootsym), *t0) lib.logger.debug(las, 'Block Hamiltonian - ecore:') lib.logger.debug(las, '{}'.format(ham_blk)) lib.logger.debug(las, 'Block S**2:') lib.logger.debug(las, '{}'.format(s2_blk)) lib.logger.debug(las, 'Block overlap matrix:') lib.logger.debug(las, '{}'.format(ovlp_blk)) s2_mat[np.ix_(idx, idx)] = s2_blk diag_test = np.diag(ham_blk) diag_ref = las.e_states[idx] - e0 lib.logger.debug( las, '{:>13s} {:>13s} {:>13s}'.format('Diagonal', 'Reference', 'Error')) for ix, (test, ref) in enumerate(zip(diag_test, diag_ref)): lib.logger.debug( las, '{:13.6e} {:13.6e} {:13.6e}'.format(test, ref, test - ref)) assert ( np.allclose(diag_test, diag_ref, atol=1e-5) ), 'SI Hamiltonian diagonal element error. Inadequate convergence?' e, c = linalg.eigh(ham_blk, b=ovlp_blk) s2_blk = c.conj().T @ s2_blk @ c lib.logger.debug(las, 'Block S**2 in adiabat basis:') lib.logger.debug(las, '{}'.format(s2_blk)) e_roots[idx] = e s2_roots[idx] = np.diag(s2_blk) si[np.ix_(idx, idx)] = c idx = np.argsort(e_roots) rootsym = np.array(statesym)[idx] e_roots = e_roots[idx] + e0 s2_roots = s2_roots[idx] nelec_roots = [statesym[ix][0:2] for ix in idx] wfnsym_roots = [statesym[ix][2] for ix in idx] si = si[:, idx] si = tag_array(si, s2=s2_roots, s2_mat=s2_mat, nelec=nelec_roots, wfnsym=wfnsym_roots) lib.logger.info(las, 'LASSI eigenvalues:') lib.logger.info( las, ' {:2s} {:>16s} {:6s} {:6s} {:6s} {:6s}'.format( 'ix', 'Energy', 'Neleca', 'Nelecb', '<S**2>', 'Wfnsym')) for ix, (er, s2r, rsym) in enumerate(zip(e_roots, s2_roots, rootsym)): neleca, nelecb, wfnsym = rsym wfnsym = symm.irrep_id2name(las.mol.groupname, wfnsym) lib.logger.info( las, ' {:2d} {:16.10f} {:6d} {:6d} {:6.3f} {:>6s}'.format( ix, er, neleca, nelecb, s2r, wfnsym)) return e_roots, si