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) 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]] if mol.cart: deg = (l + 1) * (l + 2) // 2 else: deg = 2 * l + 1 for n in range(nc): if l > 3: rydbg_lst.extend(range(k, k + deg)) elif ecpcore[l] + count[ia, l] + n < coreshell[l]: core_lst.extend(range(k, k + deg)) elif ecpcore[l] + count[ia, l] + n < cvshell[l]: val_lst.extend(range(k, k + deg)) else: rydbg_lst.extend(range(k, k + deg)) k = k + deg count[ia, l] += nc return core_lst, val_lst, rydbg_lst
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]] if mol.cart: deg = (l + 1) * (l + 2) // 2 else: deg = 2 * l + 1 for n in range(nc): if l > 3: rydbg_lst.extend(range(k, k+deg)) elif ecpcore[l]+count[ia,l]+n < coreshell[l]: core_lst.extend(range(k, k+deg)) elif ecpcore[l]+count[ia,l]+n < cvshell[l]: val_lst.extend(range(k, k+deg)) else: rydbg_lst.extend(range(k, k+deg)) k = k + deg 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: # Put random charges on the decorated atoms fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi - 2 elif mole.is_ghost_atom(k): if ksymb == 'X' or ksymb.upper() == 'GHOST': fake_chgs.append([.3] * len(lst)) elif ksymb[0] == 'X': fake_chgs.append([mole.charge(ksymb[1:]) + .3] * len(lst)) elif ksymb[:5] == 'GHOST': fake_chgs.append([mole.charge(ksymb[5:]) + .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 __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 mole.is_ghost_atom(k): if ksymb == 'X' or ksymb.upper() == 'GHOST': fake_chgs.append([.3] * len(lst)) elif ksymb[0] == 'X': fake_chgs.append([mole.charge(ksymb[1:])+.3] * len(lst)) elif ksymb[:5] == 'GHOST': fake_chgs.append([mole.charge(ksymb[5:])+.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 set_atom_conf(element, description): '''Change the default atomic core and valence configuration to the one given by "description". See data/elements.py 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 data/elements.py 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 get_nuc_g_factor(symb_or_charge, mass=None): if isinstance(symb_or_charge, str): Z = mole.charge(symb_or_charge) else: Z = symb_or_charge # g factor of other isotopes can be found in file nuclear_g_factor.dat if mass is None: # The default isotopes nuc_spin, g_nuc = ISOTOPE_GYRO[Z][0][1:3] else: for isotop_mass, nuc_spin, g_nuc in ISOTOPE_GYRO[Z]: if isotop_mass == mass: break else: raise ValueError('mass=%s not found in isotopes of %s' % (mass, symb_or_charge)) #gyromag = g_factor_to_gyromagnetic_ratio(g_nuc) return g_nuc
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_GYRO[Z][1:3] #gyromag = g_factor_to_gyromagnetic_ratio(g_nuc) return g_nuc