Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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))
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
 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))
Ejemplo n.º 8
0
 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))
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
 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
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
 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
Ejemplo n.º 16
0
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)
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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')
Ejemplo n.º 21
0
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
Ejemplo n.º 22
0
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
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    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
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
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)
Ejemplo n.º 27
0
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
Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
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
Ejemplo n.º 30
0
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
Ejemplo n.º 31
0
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
Ejemplo n.º 32
0
    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
Ejemplo n.º 33
0
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
Ejemplo n.º 34
0
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)
Ejemplo n.º 35
0
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