def mulliken_meta(cell, dm_ao_kpts, verbose=logger.DEBUG, pre_orth_method=PRE_ORTH_METHOD, s=None): '''A modified Mulliken population analysis, based on meta-Lowdin AOs. Note this function only computes the Mulliken population for the gamma point density matrix. ''' from pyscf.lo import orth if s is None: s = get_ovlp(cell) log = logger.new_logger(cell, verbose) log.note('Analyze output for *gamma point*') log.info(' To include the contributions from k-points, transform to a ' 'supercell then run the population analysis on the supercell\n' ' from pyscf.pbc.tools import k2gamma\n' ' k2gamma.k2gamma(mf).mulliken_meta()') log.note("KRHF mulliken_meta") dm_ao_gamma = dm_ao_kpts[0, :, :].real s_gamma = s[0, :, :].real c = orth.restore_ao_character(cell, pre_orth_method) orth_coeff = orth.orth_ao(cell, 'meta_lowdin', pre_orth_ao=c, s=s_gamma) c_inv = np.dot(orth_coeff.T, s_gamma) dm = reduce(np.dot, (c_inv, dm_ao_gamma, c_inv.T.conj())) log.note(' ** Mulliken pop on meta-lowdin orthogonal AOs **') return mol_hf.mulliken_pop(cell, dm, np.eye(orth_coeff.shape[0]), log)
def mulliken_meta(cell, dm_ao_kpts, verbose=logger.DEBUG, pre_orth_method=PRE_ORTH_METHOD, s=None): '''A modified Mulliken population analysis, based on meta-Lowdin AOs. Note this function only computes the Mulliken population for the gamma point density matrix. ''' from pyscf.lo import orth if s is None: s = khf.get_ovlp(cell) log = logger.new_logger(cell, verbose) log.note('Analyze output for *gamma point*.') log.info(' To include the contributions from k-points, transform to a ' 'supercell then run the population analysis on the supercell\n' ' from pyscf.pbc.tools import k2gamma\n' ' k2gamma.k2gamma(mf).mulliken_meta()') log.note("KUHF mulliken_meta") dm_ao_gamma = dm_ao_kpts[:,0,:,:].real s_gamma = s[0,:,:].real c = orth.restore_ao_character(cell, pre_orth_method) orth_coeff = orth.orth_ao(cell, 'meta_lowdin', pre_orth_ao=c, s=s_gamma) c_inv = np.dot(orth_coeff.T, s_gamma) dm_a = reduce(np.dot, (c_inv, dm_ao_gamma[0], c_inv.T.conj())) dm_b = reduce(np.dot, (c_inv, dm_ao_gamma[1], c_inv.T.conj())) log.note(' ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **') return mol_uhf.mulliken_pop(cell, (dm_a,dm_b), np.eye(orth_coeff.shape[0]), log)
def mulliken_meta(cell, dm_ao_kpts, verbose=logger.DEBUG, pre_orth_method=PRE_ORTH_METHOD, s=None): '''Mulliken population analysis, based on meta-Lowdin AOs. Note this function only computes the Mulliken population for the gamma point density matrix. ''' from pyscf.lo import orth if s is None: s = get_ovlp(cell) log = logger.new_logger(cell, verbose) log.note('Analyze output for the gamma point') log.note("KRHF mulliken_meta") dm_ao_gamma = dm_ao_kpts[0, :, :].real s_gamma = s[0, :, :].real c = orth.restore_ao_character(cell, pre_orth_method) orth_coeff = orth.orth_ao(cell, 'meta_lowdin', pre_orth_ao=c, s=s_gamma) c_inv = np.dot(orth_coeff.T, s_gamma) dm = reduce(np.dot, (c_inv, dm_ao_gamma, c_inv.T.conj())) log.note(' ** Mulliken pop on meta-lowdin orthogonal AOs **') return mol_hf.mulliken_pop(cell, dm, np.eye(orth_coeff.shape[0]), log)
def mulliken_meta(mol, dm_ao, verbose=logger.DEBUG, pre_orth_method=PRE_ORTH_METHOD, s=None): '''Mulliken population analysis, based on meta-Lowdin AOs. ''' from pyscf.lo import orth if s is None: s = hf.get_ovlp(mol) log = logger.new_logger(mol, verbose) if isinstance(dm_ao, numpy.ndarray) and dm_ao.ndim == 2: dm_ao = numpy.array((dm_ao*.5, dm_ao*.5)) c = orth.restore_ao_character(mol, pre_orth_method) orth_coeff = orth.orth_ao(mol, 'meta_lowdin', pre_orth_ao=c, s=s) c_inv = numpy.dot(orth_coeff.T, s) dm_a = reduce(numpy.dot, (c_inv, dm_ao[0], c_inv.T.conj())) dm_b = reduce(numpy.dot, (c_inv, dm_ao[1], c_inv.T.conj())) log.note(' ** Mulliken pop alpha/beta on meta-lowdin orthogonal AOs **') return mulliken_pop(mol, (dm_a,dm_b), numpy.eye(orth_coeff.shape[0]), log)
def atomic_pops(mol, mo_coeff, method='meta_lowdin'): ''' Kwargs: method : string one of mulliken, lowdin, meta_lowdin Returns: A 3-index tensor [A,i,j] indicates the population of any orbital-pair density |i><j| for each species (atom in this case). This tensor is used to construct the population and gradients etc. You can customize the PM localization wrt other population metric, such as the charge of a site, the charge of a fragment (a group of atoms) by overwriting this tensor. See also the example pyscf/examples/loc_orb/40-hubbard_model_PM_localization.py for the PM localization of site-based population for hubbard model. ''' if getattr(mol, 'pbc_intor', None): # whether mol object is a cell s = mol.pbc_intor('int1e_ovlp_sph', hermi=1) else: s = mol.intor_symmetric('int1e_ovlp') nmo = mo_coeff.shape[1] proj = numpy.empty((mol.natm, nmo, nmo)) if method.lower() == 'mulliken': for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): csc = reduce(numpy.dot, (mo_coeff[p0:p1].conj().T, s[p0:p1], mo_coeff)) proj[i] = (csc + csc.conj().T) * .5 elif method.lower() in ('lowdin', 'meta_lowdin'): c = orth.restore_ao_character(mol, 'ANO') csc = reduce(lib.dot, (mo_coeff.conj().T, s, orth.orth_ao(mol, method, c, s=s))) for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].conj().T) else: raise KeyError('method = %s' % method) return proj
def atomic_pops(mol, mo_coeff, method='meta_lowdin'): '''kwarg method can be one of mulliken, lowdin, meta_lowdin ''' s = mol.intor_symmetric('int1e_ovlp') nmo = mo_coeff.shape[1] proj = numpy.empty((mol.natm, nmo, nmo)) if method.lower() == 'mulliken': for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): csc = reduce(numpy.dot, (mo_coeff[p0:p1].T, s[p0:p1], mo_coeff)) proj[i] = (csc + csc.T) * .5 elif method.lower() in ('lowdin', 'meta_lowdin'): c = orth.restore_ao_character(mol, 'ANO') csc = reduce(lib.dot, (mo_coeff.T, s, orth.orth_ao(mol, method, c, s=s))) for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].T) else: raise KeyError('method = %s' % method) return proj
def atomic_pops(mol, mo_coeff, method='meta_lowdin', mf=None): ''' Kwargs: method : string The atomic population projection scheme. It can be mulliken, lowdin, meta_lowdin, iao, or becke Returns: A 3-index tensor [A,i,j] indicates the population of any orbital-pair density |i><j| for each species (atom in this case). This tensor is used to construct the population and gradients etc. You can customize the PM localization wrt other population metric, such as the charge of a site, the charge of a fragment (a group of atoms) by overwriting this tensor. See also the example pyscf/examples/loc_orb/40-hubbard_model_PM_localization.py for the PM localization of site-based population for hubbard model. ''' method = method.lower().replace('_', '-') nmo = mo_coeff.shape[1] proj = numpy.empty((mol.natm, nmo, nmo)) if getattr(mol, 'pbc_intor', None): # whether mol object is a cell s = mol.pbc_intor('int1e_ovlp_sph', hermi=1) else: s = mol.intor_symmetric('int1e_ovlp') if method == 'becke': from pyscf.dft import gen_grid if not (getattr(mf, 'grids', None) and getattr(mf, '_numint', None)): # Call DFT to initialize grids and numint objects mf = mol.RKS() grids = mf.grids ni = mf._numint if not isinstance(grids, gen_grid.Grids): raise NotImplementedError('PM becke scheme for PBC systems') # The atom-wise Becke grids (without concatenated to a vector of grids) coords, weights = grids.get_partition(mol, concat=False) for i in range(mol.natm): ao = ni.eval_ao(mol, coords[i], deriv=0) aow = numpy.einsum('pi,p->pi', ao, weights[i]) charge_matrix = lib.dot(aow.conj().T, ao) proj[i] = reduce(lib.dot, (mo_coeff.conj().T, charge_matrix, mo_coeff)) elif method == 'mulliken': for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): csc = reduce(numpy.dot, (mo_coeff[p0:p1].conj().T, s[p0:p1], mo_coeff)) proj[i] = (csc + csc.conj().T) * .5 elif method in ('lowdin', 'meta-lowdin'): c = orth.restore_ao_character(mol, 'ANO') #csc = reduce(lib.dot, (mo_coeff.conj().T, s, orth_local_ao_coeff)) csc = reduce(lib.dot, (mo_coeff.conj().T, s, orth.orth_ao(mol, method, c, s=s))) for i, (b0, b1, p0, p1) in enumerate(mol.offset_nr_by_atom()): proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].conj().T) elif method in ('iao', 'ibo'): from pyscf.lo import iao assert mf is not None # FIXME: How to handle UHF/UKS object? orb_occ = mf.mo_coeff[:, mf.mo_occ > 0] iao_coeff = iao.iao(mol, orb_occ) # # IAO is generally not orthogonalized. For simplicity, we take Lowdin # orthogonalization here. Other orthogonalization can be used. Results # should be very closed to the Lowdin-orth orbitals # # PM with Mulliken population of non-orth IAOs can be found in # ibo.PipekMezey function # iao_coeff = orth.vec_lowdin(iao_coeff, s) csc = reduce(lib.dot, (mo_coeff.conj().T, s, iao_coeff)) iao_mol = iao.reference_mol(mol) for i, (b0, b1, p0, p1) in enumerate(iao_mol.offset_nr_by_atom()): proj[i] = numpy.dot(csc[:, p0:p1], csc[:, p0:p1].conj().T) else: raise KeyError('method = %s' % method) return proj