def aug_etb_for_dfbasis(mol, dfbasis=DFBASIS, beta=ETB_BETA, start_at=FIRST_ETB_ELEMENT): '''augment weigend basis with even-tempered gaussian basis exps = alpha*beta^i for i = 1..N ''' nuc_start = gto.charge(start_at) uniq_atoms = set([a[0] for a in mol._atom]) newbasis = {} for symb in uniq_atoms: nuc_charge = gto.charge(symb) if nuc_charge < nuc_start: newbasis[symb] = dfbasis #?elif symb in mol._ecp: else: conf = elements.CONFIGURATION[nuc_charge] max_shells = 4 - conf.count(0) emin_by_l = [1e99] * 8 emax_by_l = [0] * 8 l_max = 0 for b in mol._basis[symb]: l = b[0] l_max = max(l_max, l) if l >= max_shells+1: continue if isinstance(b[1], int): e_c = numpy.array(b[2:]) else: e_c = numpy.array(b[1:]) es = e_c[:,0] cs = e_c[:,1:] es = es[abs(cs).max(axis=1) > 1e-3] emax_by_l[l] = max(es.max(), emax_by_l[l]) emin_by_l[l] = min(es.min(), emin_by_l[l]) l_max1 = l_max + 1 emin_by_l = numpy.array(emin_by_l[:l_max1]) emax_by_l = numpy.array(emax_by_l[:l_max1]) # Estimate the exponents ranges by geometric average emax = numpy.sqrt(numpy.einsum('i,j->ij', emax_by_l, emax_by_l)) emin = numpy.sqrt(numpy.einsum('i,j->ij', emin_by_l, emin_by_l)) liljsum = numpy.arange(l_max1)[:,None] + numpy.arange(l_max1) emax_by_l = [emax[liljsum==ll].max() for ll in range(l_max1*2-1)] emin_by_l = [emin[liljsum==ll].min() for ll in range(l_max1*2-1)] # Tune emin and emax emin_by_l = numpy.array(emin_by_l) * 2 # *2 for alpha+alpha on same center emax_by_l = numpy.array(emax_by_l) * 2 #/ (numpy.arange(l_max1*2-1)*.5+1) ns = numpy.log((emax_by_l+emin_by_l)/emin_by_l) / numpy.log(beta) etb = [] for l, n in enumerate(numpy.ceil(ns).astype(int)): if n > 0: etb.append((l, n, emin_by_l[l], beta)) newbasis[symb] = gto.expand_etbs(etb) return newbasis
def get_atm_nrhf(mol): if mol.has_ecp(): raise NotImplementedError('Atomic calculation with ECP is not implemented') atm_scf_result = {} for a, b in mol._basis.items(): atm = gto.Mole() atm.stdout = mol.stdout atm.atom = atm._atom = [[a, (0, 0, 0)]] atm._basis = {a: b} atm.nelectron = gto.charge(a) atm.spin = atm.nelectron % 2 atm._atm, atm._bas, atm._env = \ atm.make_env(atm._atom, atm._basis, atm._env) atm._built = True if atm.nelectron == 0: # GHOST nao = atm.nao_nr() mo_occ = mo_energy = numpy.zeros(nao) mo_coeff = numpy.zeros((nao,nao)) atm_scf_result[a] = (0, mo_energy, mo_coeff, mo_occ) else: atm_hf = AtomSphericAverageRHF(atm) atm_hf.verbose = 0 atm_scf_result[a] = atm_hf.scf()[1:] atm_hf._eri = None mol.stdout.flush() return atm_scf_result
def print_geometry_header(self): ''' Atoms written in order of increasing ia ''' #Write number of atom types, number of atoms self.out_file.write('\' * Geometry section\'\n') self.out_file.write('3\t\t\tndim\n') self.out_file.write('%d %d\t\t\tnctypes, ncent\n' % (len(self.atoms), self.mol.natm)) #For each atom, write the atom type ia2species = [ self.atoms.index(self.mol.atom_symbol(ia)) + 1 for ia in range(self.mol.natm) ] self.out_file.write(' '.join([str(species) for species in ia2species])) self.out_file.write('\t\t\t(iwctype(i), i= 1,ncent)\n') #For each atom type, write Z self.out_file.write(' '.join( [str(gto.charge(atom)) for atom in self.atoms])) self.out_file.write('\t\t\t(znuc(i), i=1, nctype)\n') #For each atom, write the coordinates/atom type for ia in range(self.mol.natm): self.out_file.write('%E\t%E\t%E\t%d\n' % (tuple(self.mol.atom_coord(ia)) + (ia2species[ia], ))) self.out_file.write('\n') return
def get_atm_nrhf(mol, atomic_configuration=elements.NRSRHF_CONFIGURATION): atm_scf_result = {} for a, b in mol._basis.items(): atm = gto.Mole() atm.stdout = mol.stdout atm.atom = atm._atom = [[a, (0, 0, 0)]] atm._basis = {a: b} atm.nelectron = gto.charge(a) atm.spin = atm.nelectron % 2 atm._atm, atm._bas, atm._env = \ atm.make_env(atm._atom, atm._basis, atm._env) if a in mol._ecp: atm._ecp[a] = mol._ecp[a] atm._atm, atm._ecpbas, atm._env = \ atm.make_ecp_env(atm._atm, atm._ecp, atm._env) atm._built = True if atm.nelectron == 0: # GHOST nao = atm.nao_nr() mo_occ = mo_energy = numpy.zeros(nao) mo_coeff = numpy.zeros((nao, nao)) atm_scf_result[a] = (0, mo_energy, mo_coeff, mo_occ) else: atm_hf = AtomSphericAverageRHF(atm) atm_hf.atomic_configuration = atomic_configuration atm_hf.verbose = 0 atm_hf.run() atm_scf_result[a] = (atm_hf.e_tot, atm_hf.mo_energy, atm_hf.mo_coeff, atm_hf.mo_occ) atm_hf._eri = None mol.stdout.flush() return atm_scf_result
def kernel(self): mol = self.mol basis_type = _get_basis_type(mol) if self.xc in FUNC_CODE: func, supported_versions = FUNC_CODE[self.xc] if func == 'b3lyp' and basis_type == '6-31gd': func, supported_versions = FUNC_CODE['B3LYP/631GD'] elif func == 'hf' and basis_type == 'sv': func, supported_versions = FUNC_CODE['HF/SV'] else: raise RuntimeError('Functional %s not found' % self.xc) assert (self.version in supported_versions) # dft-d3 has special treatment for def2-TZ basis tz = (basis_type == 'def2-TZ') coords = mol.atom_coords() nuc_types = [gto.charge(mol.atom_symbol(ia)) for ia in range(mol.natm)] nuc_types = numpy.asarray(nuc_types, dtype=numpy.int32) edisp = ctypes.c_double(0) grads = numpy.zeros((mol.natm, 3)) drv = self.libdftd3.wrapper drv(ctypes.c_int(mol.natm), coords.ctypes.data_as(ctypes.c_void_p), nuc_types.ctypes.data_as(ctypes.c_void_p), ctypes.c_char_p(func), ctypes.c_int(self.version), ctypes.c_int(tz), ctypes.byref(edisp), grads.ctypes.data_as(ctypes.c_void_p)) self.edisp = edisp.value self.grads = grads return edisp.value, grads
def write(self, field, fname, comment=None): """ Result: .cube file with the field in the file fname. """ assert (field.ndim == 3) assert (field.shape == (self.nx, self.ny, self.nz)) if comment is None: comment = 'Generic field? Supply the optional argument "comment" to define this line' mol = self.mol coord = mol.atom_coords() with open(fname, 'w') as f: f.write(comment + '\n') f.write('PySCF Version: %s Date: %s\n' % (pyscf.__version__, time.ctime())) f.write('%5d' % mol.natm) f.write('%12.6f%12.6f%12.6f\n' % tuple(self.boxorig.tolist())) f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nx, self.xs[1], 0, 0)) f.write('%5d%12.6f%12.6f%12.6f\n' % (self.ny, 0, self.ys[1], 0)) f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nz, 0, 0, self.zs[1])) for ia in range(mol.natm): atmsymb = mol.atom_symbol(ia) f.write('%5d%12.6f' % (gto.charge(atmsymb), 0.)) f.write('%12.6f%12.6f%12.6f\n' % tuple(coord[ia])) for ix in range(self.nx): for iy in range(self.ny): for iz0, iz1 in lib.prange(0, self.nz, 6): fmt = '%13.5E' * (iz1 - iz0) + '\n' f.write(fmt % tuple(field[ix, iy, iz0:iz1].tolist()))
def write_header(self, filename, dset_ids=None): """Write header of cube-file.""" if self.nfields > 1 and dset_ids is None: dset_ids = range(1, self.nfields + 1) with open(filename, 'w') as f: f.write('%s\n' % self.title) f.write('%s\n' % self.comment) if self.nfields > 1: f.write('%5d' % -self.cell.natm) else: f.write('%5d' % self.cell.natm) f.write('%12.6f%12.6f%12.6f' % tuple(self.origin)) if self.nfields > 1: f.write('%5d' % self.nfields) f.write('\n') # Lattice vectors f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nx, *(self.a[0] / (self.nx - 1)))) f.write('%5d%12.6f%12.6f%12.6f\n' % (self.ny, *(self.a[1] / (self.ny - 1)))) f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nz, *(self.a[2] / (self.nz - 1)))) # Atoms for atm in range(self.cell.natm): sym = self.cell.atom_symbol(atm) f.write('%5d%12.6f' % (gto.charge(sym), 0.0)) f.write('%12.6f%12.6f%12.6f\n' % tuple(self.cell.atom_coords()[atm])) # Data set indices if self.nfields > 1: f.write('%5d' % self.nfields) for i in range(self.nfields): f.write('%5d' % dset_ids[i]) f.write('\n')
def gen_atomic_grids(mol, atom_grid={}, radi_method=radi.gauss_chebyshev, level=3, prune=nwchem_prune, **kwargs): '''Generate number of radial grids and angular grids for the given molecule. Returns: A dict, with the atom symbol for the dict key. For each atom type, the dict value has two items: one is the meshgrid coordinates wrt the atom center; the second is the volume of that grid. ''' if isinstance(atom_grid, (list, tuple)): atom_grid = dict([(mol.atom_symbol(ia), atom_grid) for ia in range(mol.natm)]) atom_grids_tab = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in atom_grids_tab: chg = gto.charge(symb) if symb in atom_grid: n_rad, n_ang = atom_grid[symb] if n_ang not in LEBEDEV_NGRID: if n_ang in LEBEDEV_ORDER: logger.warn(mol, 'n_ang %d for atom %d %s is not ' 'the supported Lebedev angular grids. ' 'Set n_ang to %d', n_ang, ia, symb, LEBEDEV_ORDER[n_ang]) n_ang = LEBEDEV_ORDER[n_ang] else: raise ValueError('Unsupported angular grids %d' % n_ang) else: n_rad = _default_rad(chg, level) n_ang = _default_ang(chg, level) rad, dr = radi_method(n_rad, chg, ia, **kwargs) rad_weight = 4*numpy.pi * rad**2 * dr if callable(prune): angs = prune(chg, rad, n_ang) else: angs = [n_ang] * n_rad logger.debug(mol, 'atom %s rad-grids = %d, ang-grids = %s', symb, n_rad, angs) angs = numpy.array(angs) coords = [] vol = [] for n in sorted(set(angs)): grid = numpy.empty((n,4)) libdft.MakeAngularGrid(grid.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(n)) idx = numpy.where(angs==n)[0] for i0, i1 in prange(0, len(idx), 12): # 12 radi-grids as a group coords.append(numpy.einsum('i,jk->jik',rad[idx[i0:i1]], grid[:,:3]).reshape(-1,3)) vol.append(numpy.einsum('i,j->ji', rad_weight[idx[i0:i1]], grid[:,3]).ravel()) atom_grids_tab[symb] = (numpy.vstack(coords), numpy.hstack(vol)) return atom_grids_tab
def frac_occ(symb, l): nuc = gto.charge(symb) if l < 4 and elements.CONFIGURATION[nuc][l] > 0: ne = elements.CONFIGURATION[nuc][l] nd = (l * 2 + 1) * 2 ndocc = ne.__floordiv__(nd) frac = (float(ne) / nd - ndocc) * 2 else: ndocc = frac = 0 return ndocc, frac
def frac_occ(symb, l, atomic_configuration=elements.NRSRHF_CONFIGURATION): nuc = gto.charge(symb) if l < 4 and atomic_configuration[nuc][l] > 0: ne = atomic_configuration[nuc][l] nd = (l * 2 + 1) * 2 ndocc = ne.__floordiv__(nd) frac = (float(ne) / nd - ndocc) * 2 else: ndocc = frac = 0 return ndocc, frac
def plot_mesh_3d(mesh, weight=False, **kwargs): '''Plot atoms and grid points in a 3d plot. Args: mesh : Object of class :class:`Grids`. Kwargs: weight : bool or int Scale grid points by their weights when set to ``True``. Integers will scale grid points. ''' # Initialize logger verbose = mesh.verbose log = logger.Logger(stdout, verbose) # Handle user inputs if not isinstance(mesh, Grids): log.error('The mesh parameter has to be a Grids object.') if not isinstance(weight, bool) and not isinstance(weight, int): log.error('The weight parameter has to be a boolean or an integer.') mol = mesh.mol coords = mesh.coords atoms = mol.atom_coords() if weight and isinstance(weight, bool): weights = abs(mesh.weights) elif weight and isinstance(weight, int): weights = weight else: weights = 2 # Get the atom colors and radii (scale with 100 to make it look good) colors = [] radii = [] for ia in range(mol.natm): colors.append(cpk_colors.get(mol.atom_symbol(ia), 'magenta')) radii.append(BRAGG_RADII[charge(mol.atom_symbol(ia))] * 100) fig = plt.figure() ax = fig.add_subplot(111, projection=Axes3D.name) # Plot atoms ax.scatter(atoms[:, 0], atoms[:, 1], atoms[:, 2], s=radii, c=colors, edgecolors='k', depthshade=0) # Plot mesh points ax.scatter(coords[:, 0], coords[:, 1], coords[:, 2], s=weights, c='g') ax.set_xlabel('x-axis', fontsize=12) ax.set_ylabel('y-axis', fontsize=12) ax.set_zlabel('z-axis', fontsize=12) plt.tight_layout() plt.show() return
def get_atomic_radii(pcmobj): mol = pcmobj.mol vdw_radii = pcmobj.radii_table atom_radii = pcmobj.atom_radii atom_symb = [mol.atom_symbol(i) for i in range(mol.natm)] r_vdw = [vdw_radii[gto.charge(x)] for x in atom_symb] if atom_radii is not None: for i in range(mol.natm): if atom_symb[i] in atom_radii: r_vdw[i] = atom_radii[atom_symb[i]] return numpy.asarray(r_vdw)
def project_mol(mol, dual_basis={}): from pyscf import df uniq_atoms = set([a[0] for a in mol._atom]) newbasis = {} for symb in uniq_atoms: if gto.charge(symb) <= 10: newbasis[symb] = '321g' elif gto.charge(symb) <= 12: newbasis[symb] = 'dzp' elif gto.charge(symb) <= 18: newbasis[symb] = 'dz' elif gto.charge(symb) <= 86: newbasis[symb] = 'dzp' else: newbasis[symb] = 'sto3g' if isinstance(dual_basis, (dict, tuple, list)): newbasis.update(dual_basis) elif isinstance(dual_basis, str): for k in newbasis: newbasis[k] = dual_basis return df.addons.make_auxmol(mol, newbasis)
def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore): ecp_ao_loc = atm_ecp.ao_loc_nr() ano_ao_loc = atm_ano.ao_loc_nr() ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1] ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1] ecp_bas_l = [[atm_ecp.bas_angular(i)] * d for i, d in enumerate(ecp_ao_dim)] ano_bas_l = [[atm_ano.bas_angular(i)] * d for i, d in enumerate(ano_ao_dim)] ecp_bas_l = numpy.hstack(ecp_bas_l) ano_bas_l = numpy.hstack(ano_bas_l) nelec_core = 0 ecp_occ_tmp = [] ecp_idx = [] ano_idx = [] for l in range(4): nocc, frac = atom_hf.frac_occ(stdsymb, l) l_occ = [2] * ((nocc - ecpcore[l]) * (2 * l + 1)) if frac > 1e-15: l_occ.extend([frac] * (2 * l + 1)) nocc += 1 if nocc == 0: break nelec_core += 2 * ecpcore[l] * (2 * l + 1) i0 = ecpcore[l] * (2 * l + 1) i1 = nocc * (2 * l + 1) ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0]) ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1]) ecp_occ_tmp.append(l_occ[:i1 - i0]) ecp_idx = numpy.hstack(ecp_idx) ano_idx = numpy.hstack(ano_idx) ecp_occ = numpy.zeros(atm_ecp.nao_nr()) ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp) nelec_valence_left = int( gto.charge(stdsymb) - nelec_core - sum(ecp_occ[ecp_idx])) if nelec_valence_left > 0: logger.warn( mol, 'Characters of %d valence electrons are not identified.\n' 'It can affect the "meta-lowdin" localization method ' 'and the population analysis of SCF method.\n' 'Adjustment to the core/valence partition may be needed ' '(see function lo.nao.set_atom_conf)\nto get reasonable ' 'local orbitals or Mulliken population.\n', nelec_valence_left) # Return 0 to force the projection to ANO basis return 0 else: s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:, ano_idx] return numpy.linalg.det(s12)
def get_ang(symb, level): '''Get angular grids. Args: symb : str Atom type identifier. level : int Grid level of atom type. Returns: int Amount of angular grids. ''' try: return ang[symb][level] except (KeyError, TypeError): return dft.gen_grid._default_ang(gto.charge(symb), level)
def symm_identical_atoms(gpname, atoms): ''' Requires ''' from pyscf import gto # Dooh Coov for linear molecule if gpname == 'Dooh': coords = numpy.array([a[1] for a in atoms], dtype=float) idx0 = argsort_coords(coords) coords0 = coords[idx0] opdic = symm_ops(gpname) newc = numpy.dot(coords, opdic['sz']) idx1 = argsort_coords(newc) dup_atom_ids = numpy.sort((idx0,idx1), axis=0).T uniq_idx = numpy.unique(dup_atom_ids[:,0], return_index=True)[1] eql_atom_ids = dup_atom_ids[uniq_idx] eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids] return eql_atom_ids elif gpname == 'Coov': eql_atom_ids = [[i] for i,a in enumerate(atoms)] return eql_atom_ids charges = numpy.array([gto.charge(a[0]) for a in atoms]) coords = numpy.array([a[1] for a in atoms]) center = numpy.einsum('z,zr->r', charges, coords)/charges.sum() # if not numpy.allclose(center, 0, atol=TOLERANCE): # sys.stderr.write('WARN: Molecular charge center %s is not on (0,0,0)\n' # % center) opdic = symm_ops(gpname) ops = [opdic[op] for op in OPERATOR_TABLE[gpname]] idx = argsort_coords(coords) coords0 = coords[idx] dup_atom_ids = [] for op in ops: newc = numpy.dot(coords, op) idx = argsort_coords(newc) if not numpy.allclose(coords0, newc[idx], atol=TOLERANCE): raise RuntimeError('Symmetry identical atoms not found') dup_atom_ids.append(idx) dup_atom_ids = numpy.sort(dup_atom_ids, axis=0).T uniq_idx = numpy.unique(dup_atom_ids[:,0], return_index=True)[1] eql_atom_ids = dup_atom_ids[uniq_idx] eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids] return eql_atom_ids
def symm_identical_atoms(gpname, atoms): ''' Requires ''' from pyscf import gto # Dooh Coov for linear molecule if gpname == 'Dooh': coords = numpy.array([a[1] for a in atoms], dtype=float) idx0 = argsort_coords(coords) coords0 = coords[idx0] opdic = symm_ops(gpname) newc = numpy.dot(coords, opdic['sz']) idx1 = argsort_coords(newc) dup_atom_ids = numpy.sort((idx0, idx1), axis=0).T uniq_idx = numpy.unique(dup_atom_ids[:, 0], return_index=True)[1] eql_atom_ids = dup_atom_ids[uniq_idx] eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids] return eql_atom_ids elif gpname == 'Coov': eql_atom_ids = [[i] for i, a in enumerate(atoms)] return eql_atom_ids charges = numpy.array([gto.charge(a[0]) for a in atoms]) coords = numpy.array([a[1] for a in atoms]) center = numpy.einsum('z,zr->r', charges, coords) / charges.sum() # if not numpy.allclose(center, 0, atol=TOLERANCE): # sys.stderr.write('WARN: Molecular charge center %s is not on (0,0,0)\n' # % center) opdic = symm_ops(gpname) ops = [opdic[op] for op in OPERATOR_TABLE[gpname]] idx = argsort_coords(coords) coords0 = coords[idx] dup_atom_ids = [] for op in ops: newc = numpy.dot(coords, op) idx = argsort_coords(newc) if not numpy.allclose(coords0, newc[idx], atol=TOLERANCE): raise RuntimeError('Symmetry identical atoms not found') dup_atom_ids.append(idx) dup_atom_ids = numpy.sort(dup_atom_ids, axis=0).T uniq_idx = numpy.unique(dup_atom_ids[:, 0], return_index=True)[1] eql_atom_ids = dup_atom_ids[uniq_idx] eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids] return eql_atom_ids
def get_atomic_radii(pcmobj): ''' get atomic radii for QM and MM ''' mol = pcmobj.mol mm_mol = pcmobj.mm_mol vdw_radii = pcmobj.radii_table atom_radii = pcmobj.atom_radii atom_symb = [mol.atom_symbol(i) for i in range(mol.natm)] if mm_mol is not None: atom_symb += [mm_mol.atom_symbol(i) for i in range(mm_mol.natm)] r_vdw = [vdw_radii[gto.charge(x)] for x in atom_symb] if atom_radii is not None: for i in range(len(atom_symb)): if atom_symb[i] in atom_radii: r_vdw[i] = atom_radii[atom_symb[i]] return numpy.asarray(r_vdw)
def write(self, field, fname, comment=None): """ Result: .cube file with the field in the file fname. """ assert (field.ndim == 3) assert (field.shape == (self.nx, self.ny, self.nz)) if comment is None: comment = 'Generic field? Supply the optional argument "comment" to define this line' mol = self.mol coord = mol.atom_coords() with open(fname, 'w') as f: f.write(comment + '\n') f.write( f'PySCF Version: {pyscf.__version__} Date: {time.ctime()}\n') f.write(f'{mol.natm:5d}') f.write('%12.6f%12.6f%12.6f\n' % tuple(self.boxorig.tolist())) dx = self.xs[-1] if len(self.xs) == 1 else self.xs[1] dy = self.ys[-1] if len(self.ys) == 1 else self.ys[1] dz = self.zs[-1] if len(self.zs) == 1 else self.zs[1] delta = (self.box.T * [dx, dy, dz]).T f.write( f'{self.nx:5d}{delta[0,0]:12.6f}{delta[0,1]:12.6f}{delta[0,2]:12.6f}\n' ) f.write( f'{self.ny:5d}{delta[1,0]:12.6f}{delta[1,1]:12.6f}{delta[1,2]:12.6f}\n' ) f.write( f'{self.nz:5d}{delta[2,0]:12.6f}{delta[2,1]:12.6f}{delta[2,2]:12.6f}\n' ) for ia in range(mol.natm): atmsymb = mol.atom_symbol(ia) f.write('%5d%12.6f' % (gto.charge(atmsymb), 0.)) f.write('%12.6f%12.6f%12.6f\n' % tuple(coord[ia])) for ix in range(self.nx): for iy in range(self.ny): for iz0, iz1 in lib.prange(0, self.nz, 6): fmt = '%13.5E' * (iz1 - iz0) + '\n' f.write(fmt % tuple(field[ix, iy, iz0:iz1].tolist()))
def kernel(self): mol = self.mol basis_type = _get_basis_type(mol) if self.xc in FUNC_CODE: func, supported_versions = FUNC_CODE[self.xc] if func == 'b3lyp' and basis_type == '6-31gd': func, supported_versions = FUNC_CODE['B3LYP/631GD'] elif func == 'hf' and basis_type == 'sv': func, supported_versions = FUNC_CODE['HF/SV'] else: raise RuntimeError('Functional %s not found' % self.xc) assert(self.version in supported_versions) # dft-d3 has special treatment for def2-TZ basis tz = (basis_type == 'def2-TZ') coords = mol.atom_coords() nuc_types = [gto.charge(mol.atom_symbol(ia)) for ia in range(mol.natm)] nuc_types = numpy.asarray(nuc_types, dtype=numpy.int32) edisp = ctypes.c_double(0) grads = numpy.zeros((mol.natm,3)) drv = self.libdftd3.wrapper drv(ctypes.c_int(mol.natm), coords.ctypes.data_as(ctypes.c_void_p), nuc_types.ctypes.data_as(ctypes.c_void_p), ctypes.c_char_p(func), ctypes.c_int(self.version), ctypes.c_int(tz), ctypes.byref(edisp), grads.ctypes.data_as(ctypes.c_void_p)) self.edisp = edisp.value self.grads = grads return edisp.value, grads
energy = energy gen_solver = as_solver = gen_ddcosmo_solver get_atomic_radii = get_atomic_radii def regularize_xt(self, t, eta, scale=1): # scale = eta*scale, is it correct? return regularize_xt(t, eta*scale) if __name__ == '__main__': from pyscf import scf from pyscf import mcscf from pyscf import cc mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1') natm = mol.natm r_vdw = [radii.VDW[gto.charge(mol.atom_symbol(i))] for i in range(natm)] r_vdw = numpy.asarray(r_vdw) pcmobj = DDCOSMO(mol) pcmobj.regularize_xt = lambda t, eta, scale: regularize_xt(t, eta) pcmobj.lebedev_order = 7 pcmobj.lmax = 6 pcmobj.eta = 0.1 nlm = (pcmobj.lmax+1)**2 coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) fi = make_fi(pcmobj, r_vdw) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) L = make_L(pcmobj, r_vdw, ylm_1sph, fi) print(lib.finger(L) - 6.2823493771037473) mol = gto.Mole()
def plot_mesh_2d(mesh, weight=False, plane='xy'): '''Project atoms and grid points to a given plane in a 2d plot. Args: mesh : Object of class :class:`Grids`. Kwargs: weight : bool or int Scale grid points by their weights when set to ``True``. Integers will scale grid points. plane : str Contains the plane to project on to. Needs two elements of ``'x'``, ``'y'``, and ``'z'``. ''' # Dictionary to map input axes to their coordinates ax = {'x': 0, 'y': 1, 'z': 2} # Initialize logger verbose = mesh.verbose log = logger.Logger(stdout, verbose) # Handle user inputs if not isinstance(mesh, Grids): log.error('The mesh parameter has to be a Grids object.') if not isinstance(weight, bool) and not isinstance(weight, int): log.error('The weight parameter has to be a boolean or an integer.') if not isinstance(plane, str): log.error('The plane parameter has to be a string.') if len(plane) != 2: log.error('The plane parameter has to be a string of length 2.') if not set(plane).issubset(ax.keys()): log.error('The plane parameter only accepts combinations of \'%s\'.', '\', \''.join(ax.keys())) ax1, ax2 = list(plane.lower()) mol = mesh.mol coords = mesh.coords atoms = mol.atom_coords() if weight and isinstance(weight, bool): weights = abs(mesh.weights) elif weight and isinstance(weight, int): weights = weight else: weights = 2 # Get the atom colors and radii (scale with 100 to make it look good) colors = [] radii = [] for ia in range(mol.natm): colors.append(cpk_colors.get(mol.atom_symbol(ia), 'magenta')) radii.append(BRAGG_RADII[charge(mol.atom_symbol(ia))] * 100) # Project atoms plt.scatter(atoms[:, ax[ax1]], atoms[:, ax[ax2]], s=radii, c=colors, edgecolors='k') # Project mesh points plt.scatter(coords[:, ax[ax1]], coords[:, ax[ax2]], s=weights, c='g') plt.xlabel(ax1 + '-axis', fontsize=12) plt.ylabel(ax2 + '-axis', fontsize=12) plt.tight_layout() plt.show() return
energy = energy gen_solver = as_solver = gen_ddcosmo_solver get_atomic_radii = get_atomic_radii def regularize_xt(self, t, eta, scale=1): # scale = eta*scale, is it correct? return regularize_xt(t, eta * scale) if __name__ == '__main__': from pyscf import scf from pyscf import mcscf from pyscf import cc mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1') natm = mol.natm r_vdw = [radii.VDW[gto.charge(mol.atom_symbol(i))] for i in range(natm)] r_vdw = numpy.asarray(r_vdw) pcmobj = DDCOSMO(mol) pcmobj.regularize_xt = lambda t, eta, scale: regularize_xt(t, eta) pcmobj.lebedev_order = 7 pcmobj.lmax = 6 pcmobj.eta = 0.1 nlm = (pcmobj.lmax + 1)**2 coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) fi = make_fi(pcmobj, r_vdw) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) L = make_L(pcmobj, r_vdw, ylm_1sph, fi) print(lib.finger(L) - 6.2823493771037473) mol = gto.Mole() mol.atom = ''' O 0.00000000 0.00000000 -0.11081188
def project_to_atomic_orbitals(mol, basname): '''projected AO = |bas><bas|ANO> ''' from pyscf.scf.addons import project_mo_nr2nr from pyscf.scf import atom_hf from pyscf.gto.ecp import core_configuration def search_atm_l(atm, l): bas_ang = atm._bas[:, gto.ANG_OF] ao_loc = atm.ao_loc_nr() idx = [] for ib in numpy.where(bas_ang == l)[0]: idx.extend(range(ao_loc[ib], ao_loc[ib + 1])) return idx # Overlap of ANO and ECP basis def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore): ecp_ao_loc = atm_ecp.ao_loc_nr() ano_ao_loc = atm_ano.ao_loc_nr() ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1] ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1] ecp_bas_l = [[atm_ecp.bas_angular(i)] * d for i, d in enumerate(ecp_ao_dim)] ano_bas_l = [[atm_ano.bas_angular(i)] * d for i, d in enumerate(ano_ao_dim)] ecp_bas_l = numpy.hstack(ecp_bas_l) ano_bas_l = numpy.hstack(ano_bas_l) nelec_core = 0 ecp_occ_tmp = [] ecp_idx = [] ano_idx = [] for l in range(4): nocc, frac = atom_hf.frac_occ(stdsymb, l) l_occ = [2] * ((nocc - ecpcore[l]) * (2 * l + 1)) if frac > 1e-15: l_occ.extend([frac] * (2 * l + 1)) nocc += 1 if nocc == 0: break nelec_core += 2 * ecpcore[l] * (2 * l + 1) i0 = ecpcore[l] * (2 * l + 1) i1 = nocc * (2 * l + 1) ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0]) ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1]) ecp_occ_tmp.append(l_occ[:i1 - i0]) ecp_idx = numpy.hstack(ecp_idx) ano_idx = numpy.hstack(ano_idx) ecp_occ = numpy.zeros(atm_ecp.nao_nr()) ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp) nelec_valence_left = int( gto.charge(stdsymb) - nelec_core - sum(ecp_occ[ecp_idx])) if nelec_valence_left > 0: logger.warn( mol, 'Characters of %d valence electrons are not identified.\n' 'It can affect the "meta-lowdin" localization method ' 'and the population analysis of SCF method.\n' 'Adjustment to the core/valence partition may be needed ' '(see function lo.nao.set_atom_conf)\nto get reasonable ' 'local orbitals or Mulliken population.\n', nelec_valence_left) # Return 0 to force the projection to ANO basis return 0 else: s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:, ano_idx] return numpy.linalg.det(s12) nelec_ecp_dic = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in nelec_ecp_dic: nelec_ecp_dic[symb] = mol.atom_nelec_core(ia) aos = {} atm = gto.Mole() atmp = gto.Mole() for symb in mol._basis.keys(): stdsymb = gto.mole._std_symbol(symb) atm._atm, atm._bas, atm._env = \ atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, []) atm.cart = mol.cart atm._built = True s0 = atm.intor_symmetric('int1e_ovlp') if gto.is_ghost_atom(symb): aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue basis_add = gto.basis.load(basname, stdsymb) atmp._atm, atmp._bas, atmp._env = \ atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, []) atmp.cart = mol.cart atmp._built = True if symb in nelec_ecp_dic and nelec_ecp_dic[symb] > 0: # If ECP basis has good atomic character, ECP basis can be used in the # localization/population analysis directly. Otherwise project ECP # basis to ANO basis. if not PROJECT_ECP_BASIS: continue ecpcore = core_configuration(nelec_ecp_dic[symb]) # Comparing to ANO valence basis, to check whether the ECP basis set has # reasonable AO-character contraction. The ANO valence AO should have # significant overlap to ECP basis if the ECP basis has AO-character. if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1: aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal())) continue else: ecpcore = [0] * 4 # MINAO for heavier elements needs to be used with pseudo potential if (basname.upper() == 'MINAO' and gto.charge(stdsymb) > 36 and symb not in nelec_ecp_dic): raise RuntimeError( 'Basis MINAO has to be used with ecp for heavy elements') ano = project_mo_nr2nr(atmp, numpy.eye(atmp.nao_nr()), atm) rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0)) c = rm_ano.copy() for l in range(param.L_MAX): idx = numpy.asarray(search_atm_l(atm, l)) nbf_atm_l = len(idx) if nbf_atm_l == 0: break idxp = numpy.asarray(search_atm_l(atmp, l)) if l < 4: idxp = idxp[ecpcore[l]:] nbf_ano_l = len(idxp) if mol.cart: degen = (l + 1) * (l + 2) // 2 else: degen = l * 2 + 1 if nbf_atm_l > nbf_ano_l > 0: # For angular l, first place the projected ANO, then the rest AOs. sdiag = reduce( numpy.dot, (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal() nleft = (nbf_atm_l - nbf_ano_l) // degen shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, degen)) shell_rest = numpy.argsort(-shell_average)[:nleft] idx_rest = [] for k in shell_rest: idx_rest.extend(idx[k * degen:(k + 1) * degen]) c[:, idx[:nbf_ano_l]] = ano[:, idxp] c[:, idx[nbf_ano_l:]] = rm_ano[:, idx_rest] elif nbf_ano_l >= nbf_atm_l > 0: # More ANOs than the mol basis functions c[:, idx] = ano[:, idxp[:nbf_atm_l]] sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c) c *= 1. / numpy.sqrt(sdiag) aos[symb] = c nao = mol.nao_nr() c = numpy.zeros((nao, nao)) p1 = 0 for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb in mol._basis: ano = aos[symb] else: ano = aos[mol.atom_pure_symbol(ia)] p0, p1 = p1, p1 + ano.shape[1] c[p0:p1, p0:p1] = ano return c