def _core_val_ryd_list(mol): from pyscf.gto.ecp import core_configuration count = numpy.zeros((mol.natm, 9), dtype=int) core_lst = [] val_lst = [] rydbg_lst = [] k = 0 for ib in range(mol.nbas): ia = mol.bas_atom(ib) # Avoid calling mol.atom_charge because we should include ECP core electrons here nuc = mole._charge(mol.atom_symbol(ia)) l = mol.bas_angular(ib) nc = mol.bas_nctr(ib) symb = mol.atom_symbol(ia) nelec_ecp = mol.atom_nelec_core(ia) ecpcore = core_configuration(nelec_ecp) coreshell = [int(x) for x in AOSHELL[nuc][0][::2]] cvshell = [int(x) for x in AOSHELL[nuc][1][::2]] for n in range(nc): if l > 3: rydbg_lst.extend(range(k, k+(2*l+1))) elif ecpcore[l]+count[ia,l]+n < coreshell[l]: core_lst.extend(range(k, k+(2*l+1))) elif ecpcore[l]+count[ia,l]+n < cvshell[l]: val_lst.extend(range(k, k+(2*l+1))) else: rydbg_lst.extend(range(k, k+(2*l+1))) k = k + 2*l+1 count[ia,l] += nc return core_lst, val_lst, rydbg_lst
def __init__(self, atoms, basis=None): self.atomtypes = mole.atom_types(atoms, basis) # fake systems, which treates the atoms of different basis as different atoms. # the fake systems do not have the same symmetry as the potential # it's only used to determine the main (Z-)axis chg1 = numpy.pi - 2 coords = [] fake_chgs = [] idx = [] for k, lst in self.atomtypes.items(): idx.append(lst) coords.append([atoms[i][1] for i in lst]) ksymb = mole._rm_digit(k) if ksymb != k or ksymb == 'GHOST': fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi-2 else: fake_chgs.append([mole._charge(ksymb)] * len(lst)) coords = numpy.array(numpy.vstack(coords), dtype=float) fake_chgs = numpy.hstack(fake_chgs) self.charge_center = numpy.einsum('i,ij->j', fake_chgs, coords)/fake_chgs.sum() coords = coords - self.charge_center self.im = numpy.einsum('i,ij,ik->jk', fake_chgs, coords, coords)/fake_chgs.sum() idx = numpy.argsort(numpy.hstack(idx)) self.atoms = numpy.hstack((fake_chgs.reshape(-1,1), coords))[idx]
def para(mol, mo1, mo_coeff, mo_occ, hfc_nuc=None): if hfc_nuc is None: hfc_nuc = range(mol.natm) effspin = mol.spin * .5 mu_B = 1 # lib.param.BOHR_MAGNETON mu_N = lib.param.PROTON_MASS * mu_B fac = lib.param.ALPHA / 2 / effspin fac *= lib.param.G_ELECTRON * mu_B * mu_N occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] nao = mo_coeff[0].shape[0] dm10 = numpy.empty((3, nao, nao)) for i in range(3): dm10[i] = reduce(numpy.dot, (mo_coeff[0], mo1[0][i], orboa.conj().T)) dm10[i] += reduce(numpy.dot, (mo_coeff[1], mo1[1][i], orbob.conj().T)) para = numpy.empty((len(hfc_nuc), 3, 3)) for n, atm_id in enumerate(hfc_nuc): Z = mole._charge(mol.atom_symbol(atm_id)) nuc_spin, g_nuc = parameters.ISOTOPE[Z][1:3] gyromag = 1e-6 / ( 2 * numpy.pi) * parameters.g_factor_to_gyromagnetic_ratio(g_nuc) mol.set_rinv_origin(mol.atom_coord(atm_id)) h01 = mol.intor_asymmetric('int1e_prinvxp', 3) para[n] = numpy.einsum('xji,yij->yx', dm10, h01) * 2 para[n] *= fac * gyromag return para
def get_inertia_momentum(atoms, basis): charge = numpy.array([mole._charge(a[0]) for a in atoms]) coords = numpy.array([a[1] for a in atoms], dtype=float) rbar = numpy.einsum('i,ij->j', charge, coords)/charge.sum() coords = coords - rbar im = numpy.einsum('i,ij,ik->jk', charge, coords, coords)/charge.sum() return im
def _core_val_ryd_list(mol): from pyscf.gto.ecp import core_configuration count = numpy.zeros((mol.natm, 9), dtype=int) core_lst = [] val_lst = [] rydbg_lst = [] k = 0 for ib in range(mol.nbas): ia = mol.bas_atom(ib) # Avoid calling mol.atom_charge because we should include ECP core electrons here nuc = mole._charge(mol.atom_symbol(ia)) l = mol.bas_angular(ib) nc = mol.bas_nctr(ib) symb = mol.atom_symbol(ia) nelec_ecp = mol.atom_nelec_core(ia) ecpcore = core_configuration(nelec_ecp) coreshell = [int(x) for x in AOSHELL[nuc][0][::2]] cvshell = [int(x) for x in AOSHELL[nuc][1][::2]] for n in range(nc): if l > 3: rydbg_lst.extend(range(k, k + (2 * l + 1))) elif ecpcore[l] + count[ia, l] + n < coreshell[l]: core_lst.extend(range(k, k + (2 * l + 1))) elif ecpcore[l] + count[ia, l] + n < cvshell[l]: val_lst.extend(range(k, k + (2 * l + 1))) else: rydbg_lst.extend(range(k, k + (2 * l + 1))) k = k + 2 * l + 1 count[ia, l] += nc return core_lst, val_lst, rydbg_lst
def __init__(self, atoms, basis=None): self.atomtypes = mole.atom_types(atoms, basis) # fake systems, which treates the atoms of different basis as different atoms. # the fake systems do not have the same symmetry as the potential # it's only used to determine the main (Z-)axis chg1 = numpy.pi - 2 coords = [] fake_chgs = [] idx = [] for k, lst in self.atomtypes.items(): idx.append(lst) coords.append([atoms[i][1] for i in lst]) ksymb = mole._rm_digit(k) if ksymb != k or ksymb == 'GHOST': # Put random charges on the decorated atoms fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi-2 else: fake_chgs.append([mole._charge(ksymb)] * len(lst)) coords = numpy.array(numpy.vstack(coords), dtype=float) fake_chgs = numpy.hstack(fake_chgs) self.charge_center = numpy.einsum('i,ij->j', fake_chgs, coords)/fake_chgs.sum() coords = coords - self.charge_center self.im = numpy.einsum('i,ij,ik->jk', fake_chgs, coords, coords)/fake_chgs.sum() idx = numpy.argsort(numpy.hstack(idx)) self.atoms = numpy.hstack((fake_chgs.reshape(-1,1), coords))[idx]
def __init__(self, atoms, basis=None): self.atomtypes = mole.atom_types(atoms, basis) # fake systems, which treates the atoms of different basis as different atoms. # the fake systems do not have the same symmetry as the potential # it's only used to determine the main (Z-)axis chg1 = numpy.pi - 2 coords = [] fake_chgs = [] idx = [] for k, lst in self.atomtypes.items(): idx.append(lst) coords.append([atoms[i][1] for i in lst]) ksymb = mole._rm_digit(k) if ksymb != k: # Put random charges on the decorated atoms fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi - 2 elif 'GHOST' in ksymb: ksymb = mole._remove_prefix_ghost(ksymb) fake_chgs.append([mole._charge(ksymb) + .3] * len(lst)) else: fake_chgs.append([mole._charge(ksymb)] * len(lst)) coords = numpy.array(numpy.vstack(coords), dtype=float) fake_chgs = numpy.hstack(fake_chgs) self.charge_center = numpy.einsum('i,ij->j', fake_chgs, coords) / fake_chgs.sum() coords = coords - self.charge_center idx = numpy.argsort(numpy.hstack(idx)) self.atoms = numpy.hstack((fake_chgs.reshape(-1, 1), coords))[idx] self.group_atoms_by_distance = [] decimals = int(-numpy.log10(TOLERANCE)) - 1 for index in self.atomtypes.values(): index = numpy.asarray(index) c = self.atoms[index, 1:] dists = numpy.around(norm(c, axis=1), decimals) u, idx = numpy.unique(dists, return_inverse=True) for i, s in enumerate(u): self.group_atoms_by_distance.append(index[idx == i])
def dia(gobj, mol, dm0, hfc_nuc=None, verbose=None): log = logger.new_logger(gobj, verbose) if hfc_nuc is None: hfc_nuc = range(mol.natm) if isinstance(dm0, numpy.ndarray) and dm0.ndim == 2: # RHF DM return numpy.zeros((3, 3)) dma, dmb = dm0 spindm = dma - dmb effspin = mol.spin * .5 mu_B = 1 # lib.param.BOHR_MAGNETON mu_N = lib.param.PROTON_MASS * mu_B fac = lib.param.ALPHA / 2 / effspin fac *= lib.param.G_ELECTRON * mu_B * mu_N coords = mol.atom_coords() ao = numint.eval_ao(mol, coords) nao = dma.shape[0] dia = [] for i, atm_id in enumerate(hfc_nuc): Z = mole._charge(mol.atom_symbol(atm_id)) nuc_spin, g_nuc = parameters.ISOTOPE[Z][1:3] # g factor of other isotopes can be found in file nuclear_g_factor.dat gyromag = 1e-6 / ( 2 * numpy.pi) * parameters.g_factor_to_gyromagnetic_ratio(g_nuc) log.info( 'Atom %d %s nuc-spin %g nuc-g-factor %g gyromagnetic ratio %g (in MHz)', atm_id, mol.atom_symbol(atm_id), nuc_spin, g_nuc, gyromag) mol.set_rinv_origin(mol.atom_coord(atm_id)) # a01p[mu,sigma] the imaginary part of integral <vec{r}/r^3 cross p> # mu = gN * I * mu_N a01p = mol.intor('int1e_sa01sp', 12).reshape(3, 4, nao, nao) h11 = a01p[:, 1:] - a01p[:, 1:].transpose(0, 1, 3, 2) e11 = numpy.einsum('xyij,ji->xy', h11, spindm) e11 *= fac * gyromag # e11 includes fermi-contact and spin-dipolar contriutions and a rank-2 contact # term. We ignore the contribution of rank-2 contact term, view it as part of # SD contribution. See also TCA, 73, 173 fermi_contact = ( 4 * numpy.pi / 3 * fac * gyromag * numpy.einsum('i,j,ji', ao[atm_id], ao[atm_id], spindm)) dip = e11 - numpy.eye(3) * fermi_contact log.info('FC %s', fermi_contact) if gobj.verbose >= logger.INFO: _write(gobj, dip, 'SD') dia.append(e11) return numpy.asarray(dia)
def set_atom_conf(element, description): '''Change the default atomic core and valence configuration to the one given by "description". See lo.nao.AOSHELL for the default configuration. Args: element : str or int Element symbol or nuclear charge description : str or a list of str | "double p" : double p shell | "double d" : double d shell | "double f" : double f shell | "polarize" : add one polarized shell | "1s1d" : keep core unchanged and set 1 s 1 d shells for valence | ("3s2p","1d") : 3 s, 2 p shells for core and 1 d shells for valence ''' charge = mole._charge(element) def to_conf(desc): desc = desc.replace(' ', '').replace('-', '').replace('_', '').lower() if "doublep" in desc: desc = '2p' elif "doubled" in desc: desc = '2d' elif "doublef" in desc: desc = '2f' elif "polarize" in desc: loc = AOSHELL[charge][1].find('0') desc = '1' + AOSHELL[charge][1][loc + 1] return desc if isinstance(description, str): c_desc, v_desc = AOSHELL[charge][0], to_conf(description) else: c_desc, v_desc = to_conf(description[0]), to_conf(description[1]) ncore = [int(x) for x in AOSHELL[charge][0][::2]] ncv = [int(x) for x in AOSHELL[charge][1][::2]] for i, s in enumerate(('s', 'p', 'd', 'f')): if s in c_desc: ncore[i] = int(c_desc.split(s)[0][-1]) if s in v_desc: ncv[i] = ncore[i] + int(v_desc.split(s)[0][-1]) c_conf = '%ds%dp%dd%df' % tuple(ncore) cv_conf = '%ds%dp%dd%df' % tuple(ncv) AOSHELL[charge] = [c_conf, cv_conf] sys.stderr.write('Update %s conf: core %s core+valence %s\n' % (element, c_conf, cv_conf))
def set_atom_conf(element, description): """Change the default atomic core and valence configuration to the one given by "description". See lo.nao.AOSHELL for the default configuration. Args: element : str or int Element symbol or nuclear charge description : str or a list of str | "double p" : double p shell | "double d" : double d shell | "double f" : double f shell | "polarize" : add one polarized shell | "1s1d" : keep core unchanged and set 1 s 1 d shells for valence | ("3s2p","1d") : 3 s, 2 p shells for core and 1 d shells for valence """ charge = mole._charge(element) def to_conf(desc): desc = desc.replace(" ", "").replace("-", "").replace("_", "").lower() if "doublep" in desc: desc = "2p" elif "doubled" in desc: desc = "2d" elif "doublef" in desc: desc = "2f" elif "polarize" in desc: loc = AOSHELL[charge][1].find("0") desc = "1" + AOSHELL[charge][1][loc + 1] return desc if isinstance(description, str): c_desc, v_desc = AOSHELL[charge][0], to_conf(description) else: c_desc, v_desc = to_conf(description[0]), to_conf(description[1]) ncore = [int(x) for x in AOSHELL[charge][0][::2]] ncv = [int(x) for x in AOSHELL[charge][1][::2]] for i, s in enumerate(("s", "p", "d", "f")): if s in c_desc: ncore[i] = int(c_desc.split(s)[0][-1]) if s in v_desc: ncv[i] = ncore[i] + int(v_desc.split(s)[0][-1]) c_conf = "%ds%dp%dd%df" % tuple(ncore) cv_conf = "%ds%dp%dd%df" % tuple(ncv) AOSHELL[charge] = [c_conf, cv_conf] sys.stderr.write("Update %s conf: core %s core+valence %s\n" % (element, c_conf, cv_conf))
def __init__(self, atoms, basis=None): self.atomtypes = mole.atom_types(atoms, basis) # fake systems, which treates the atoms of different basis as different atoms. # the fake systems do not have the same symmetry as the potential # it's only used to determine the main (Z-)axis chg1 = numpy.pi - 2 coords = [] fake_chgs = [] idx = [] for k, lst in self.atomtypes.items(): idx.append(lst) coords.append([atoms[i][1] for i in lst]) ksymb = mole._rm_digit(k) if ksymb != k or ksymb == 'GHOST': # Put random charges on the decorated atoms fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi-2 else: fake_chgs.append([mole._charge(ksymb)] * len(lst)) coords = numpy.array(numpy.vstack(coords), dtype=float) fake_chgs = numpy.hstack(fake_chgs) self.charge_center = numpy.einsum('i,ij->j', fake_chgs, coords)/fake_chgs.sum() coords = coords - self.charge_center idx = numpy.argsort(numpy.hstack(idx)) self.atoms = numpy.hstack((fake_chgs.reshape(-1,1), coords))[idx] self.group_atoms_by_distance = [] decimals = int(-numpy.log10(TOLERANCE)) - 1 for index in self.atomtypes.values(): index = numpy.asarray(index) c = self.atoms[index,1:] dists = numpy.around(norm(c, axis=1), decimals) u, idx = numpy.unique(dists, return_inverse=True) for i, s in enumerate(u): self.group_atoms_by_distance.append(index[idx == i])
def get_mass_center(atoms): mass = numpy.array([pyscf.lib.parameters.ELEMENTS[mole._charge(a[0])][1] for a in atoms]) coords = numpy.array([a[1] for a in atoms], dtype=float) rbar = numpy.einsum('i,ij->j', mass, coords)/mass.sum() return rbar
def get_charge_center(atoms): charge = numpy.array([mole._charge(a[0]) for a in atoms]) coords = numpy.array([a[1] for a in atoms], dtype=float) rbar = numpy.einsum('i,ij->j', charge, coords)/charge.sum() return rbar
def get_nuc_g_factor(symb, mass=None): Z = mole._charge(symb) # g factor of other isotopes can be found in file nuclear_g_factor.dat nuc_spin, g_nuc = ISOTOPE[Z][1:3] #gyromag = g_factor_to_gyromagnetic_ratio(g_nuc) return g_nuc