class DFTD3(_DFTD3, method_class): def __init__(self, method, with_dftd3): self.__dict__.update(method.__dict__) self.with_dftd3 = with_dftd3 self._keys.update(['with_dftd3']) def dump_flags(self, verbose=None): method_class.dump_flags(self, verbose) if self.with_dftd3: self.with_dftd3.dump_flags(verbose) return self def energy_nuc(self): # Adding DFT D3 correction to nuclear part because it is computed # based on nuclear coordinates only. It does not depend on # quantum effects. enuc = method_class.energy_nuc(self) if self.with_dftd3: enuc += self.with_dftd3.kernel()[0] return enuc def reset(self, mol=None): self.with_dftd3.reset(mol) return method_class.reset(self, mol) def nuc_grad_method(self): scf_grad = method_class.nuc_grad_method(self) return grad(scf_grad) Gradients = lib.alias(nuc_grad_method, alias_name='Gradients')
class DFTD4(_DFTD4, mf.__class__): """ Patched SCF class including DFT-D4 corrections. """ def __init__(self, method, with_dftd4: DFTD4Dispersion): self.__dict__.update(method.__dict__) self.with_dftd4 = with_dftd4 self._keys.update(["with_dftd4"]) def dump_flags(self, verbose=None) -> "DFTD4": mf.__class__.dump_flags(self, verbose) if self.with_dftd4: self.with_dftd4.dump_flags(verbose) return self def energy_nuc(self) -> float: enuc = mf.__class__.energy_nuc(self) if self.with_dftd4: enuc += self.with_dftd4.kernel()[0] return enuc def reset(self, mol=None) -> "DFTD4": self.with_dftd4.reset(mol) return mf.__class__.reset(self, mol) def nuc_grad_method(self) -> "DFTD4Grad": scf_grad = mf.__class__.nuc_grad_method(self) return grad(scf_grad) Gradients = lib.alias(nuc_grad_method, alias_name="Gradients")
class DFTD3(method_class, _DFTD3): def dump_flags(self, verbose=None): method_class.dump_flags(self, verbose) if self.with_dftd3: self.with_dftd3.dump_flags(verbose) return self def energy_nuc(self): # Adding DFT D3 correction to nuclear part because it is computed # based on nuclear coordinates only. It does not depend on # quantum effects. enuc = method_class.energy_nuc(self) if self.with_dftd3: enuc += self.with_dftd3.kernel()[0] return enuc def nuc_grad_method(self): scf_grad = method_class.nuc_grad_method(self) return grad(scf_grad) Gradients = lib.alias(nuc_grad_method, alias_name='Gradients')
class GradientsBasics(lib.StreamObject): ''' Basic nuclear gradient functions for non-relativistic methods ''' def __init__(self, method): self.verbose = method.verbose self.stdout = method.stdout self.mol = method.mol self.base = method self.max_memory = self.mol.max_memory self.atmlst = None self.de = None self._keys = set(self.__dict__.keys()) def dump_flags(self, verbose=None): log = logger.new_logger(self, verbose) log.info('\n') if hasattr(self.base, 'converged') and not self.base.converged: log.warn('Ground state %s not converged', self.base.__class__.__name__) log.info('******** %s for %s ********', self.__class__, self.base.__class__) log.info('max_memory %d MB (current use %d MB)', self.max_memory, lib.current_memory()[0]) return self def get_hcore(self, mol=None): if mol is None: mol = self.mol return get_hcore(mol) hcore_generator = hcore_generator def get_ovlp(self, mol=None): if mol is None: mol = self.mol return get_ovlp(mol) @lib.with_doc(get_jk.__doc__) def get_jk(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() cpu0 = (time.clock(), time.time()) vj, vk = get_jk(mol, dm) logger.timer(self, 'vj and vk', *cpu0) return vj, vk def get_j(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() intor = mol._add_suffix('int2e_ip1') return -_vhf.direct_mapdm(intor, 's2kl', 'lk->s1ij', dm, 3, mol._atm, mol._bas, mol._env) def get_k(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() intor = mol._add_suffix('int2e_ip1') return -_vhf.direct_mapdm(intor, 's2kl', 'jk->s1il', dm, 3, mol._atm, mol._bas, mol._env) def grad_nuc(self, mol=None, atmlst=None): if mol is None: mol = self.mol return grad_nuc(mol, atmlst) def optimizer(self, solver='geometric'): '''Geometry optimization solver Kwargs: solver (string) : geometry optimization solver, can be "geomeTRIC" (default) or "berny". ''' if solver.lower() == 'geometric': from pyscf.geomopt import geometric_solver return geometric_solver.GeometryOptimizer(self.as_scanner()) elif solver.lower() == 'berny': from pyscf.geomopt import berny_solver return berny_solver.GeometryOptimizer(self.as_scanner()) else: raise RuntimeError('Unknown geometry optimization solver %s' % solver) def grad_elec(self): raise NotImplementedError def kernel(self): raise NotImplementedError @lib.with_doc(symmetrize.__doc__) def symmetrize(self, de, atmlst=None): return symmetrize(self.mol, de, atmlst) grad = lib.alias(kernel, alias_name='grad') def _finalize(self): if self.verbose >= logger.NOTE: logger.note(self, '--------------- %s gradients ---------------', self.base.__class__.__name__) self._write(self.mol, self.de, self.atmlst) logger.note(self, '----------------------------------------------') _write = _write def as_scanner(self): '''Generate Gradients Scanner''' raise NotImplementedError
class HF(scf.hf.SCF): '''Hartree Fock for NEO Example: >>> from pyscf import neo >>> mol = neo.Mole() >>> mol.build(atom='H 0 0 0; F 0 0 0.917', basis='ccpvdz') >>> mf = neo.HF(mol) >>> mf.scf() ''' def __init__(self, mol, unrestricted=False): scf.hf.SCF.__init__(self, mol) if mol.elec.nhomo is not None: unrestricted = True self.unrestricted = unrestricted self.mf_elec = None # dm_elec will be the total density after SCF, but can be spin # densities during the SCF procedure self.dm_elec = None self.mf_nuc = [] self.dm_nuc = [] self._eri_ne = [] self._eri_nn = [] # The verbosity flag is passed now instead of when creating those mol # objects because users need time to change mol's verbose level after # the mol object is created. self.mol.elec.verbose = self.mol.verbose for i in range(mol.nuc_num): self.mol.nuc[i].verbose = self.mol.verbose # initialize sub mf objects for electrons and quantum nuclei # electronic part: if unrestricted: self.mf_elec = scf.UHF(mol.elec) else: self.mf_elec = scf.RHF(mol.elec) self.mf_elec.get_hcore = self.get_hcore_elec self.mf_elec.super_mf = self if mol.elec.nhomo is not None: self.mf_elec.get_occ = self.get_occ_elec(self.mf_elec) # nuclear part for i in range(mol.nuc_num): self.mf_nuc.append(scf.RHF(mol.nuc[i])) mf_nuc = self.mf_nuc[-1] mf_nuc.occ_state = 0 # for Delta-SCF mf_nuc.get_occ = self.get_occ_nuc(mf_nuc) mf_nuc.get_hcore = self.get_hcore_nuc mf_nuc.get_veff = self.get_veff_nuc_bare mf_nuc.energy_qmnuc = self.energy_qmnuc mf_nuc.super_mf = self self.dm_nuc.append(None) # build ne and nn ERIs if there is enough memory for i in range(mol.nuc_num): self._eri_ne.append(None) self._eri_nn.append([None] * mol.nuc_num) if mol.incore_anyway or self._is_mem_enough( mol.elec.nao_nr(), mol.nuc[i].nao_nr()): atm, bas, env = gto.conc_env(mol.nuc[i]._atm, mol.nuc[i]._bas, mol.nuc[i]._env, mol.elec._atm, mol.elec._bas, mol.elec._env) self._eri_ne[i] = \ gto.moleintor.getints('int2e_sph', atm, bas, env, shls_slice=(0, mol.nuc[i]._bas.shape[0], 0, mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0] + mol.elec._bas.shape[0], mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0] + mol.elec._bas.shape[0]), aosym='s4') for i in range(mol.nuc_num - 1): for j in range(i + 1, mol.nuc_num): if mol.incore_anyway or self._is_mem_enough( mol.nuc[i].nao_nr(), mol.nuc[j].nao_nr()): atm, bas, env = gto.conc_env( mol.nuc[i]._atm, mol.nuc[i]._bas, mol.nuc[i]._env, mol.nuc[j]._atm, mol.nuc[j]._bas, mol.nuc[j]._env) self._eri_nn[i][j] = \ gto.moleintor.getints('int2e_sph', atm, bas, env, shls_slice=(0, mol.nuc[i]._bas.shape[0], 0, mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0] + mol.nuc[j]._bas.shape[0], mol.nuc[i]._bas.shape[0], mol.nuc[i]._bas.shape[0] + mol.nuc[j]._bas.shape[0]), aosym='s4') #def dump_chk(): def _is_mem_enough(self, nao1, nao2): return nao1**2 * nao2**2 * 2 / 1e6 + lib.current_memory( )[0] < self.max_memory * .95 def get_init_guess_elec(self, mol, init_guess): if init_guess != 'chkfile': return init_guess_elec_by_calculation(mol, self.unrestricted, init_guess) else: return init_guess_elec_by_chkfile(mol, self.chkfile) def get_init_guess_nuc(self, mol, init_guess): if init_guess != 'chkfile': return init_guess_nuc_by_calculation(self.mf_nuc, mol) else: return init_guess_nuc_by_chkfile(mol, self.chkfile) def get_hcore_elec(self, mol): return get_hcore_elec(mol, self.dm_nuc, self.mol.nuc, eri_ne=self._eri_ne) def get_occ_nuc(self, mf): return get_occ_nuc(mf) def get_occ_elec(self, mf): return get_occ_elec(mf) def get_hcore_nuc(self, mol): return get_hcore_nuc(mol, self.dm_elec, self.dm_nuc, self.mol.elec, self.mol.nuc, eri_ne=self._eri_ne, eri_nn=self._eri_nn) def get_veff_nuc_bare(self, mol, dm): return get_veff_nuc_bare(mol, dm) def energy_qmnuc(self, mf, h1n, dm_nuc, veff_n=None): return energy_qmnuc(mf, h1n, dm_nuc, veff_n=veff_n) def energy_tot(self, dm_elec, dm_nuc, h1e, vhf_e, h1n, veff_n=None): return energy_tot(self.mf_elec, self.mf_nuc, dm_elec, dm_nuc, h1e, vhf_e, h1n, veff_n=veff_n) def scf(self, dm0e=None, dm0n=[], **kwargs): cput0 = (logger.process_clock(), logger.perf_counter()) self.dump_flags() if self.max_cycle > 0 or self.mo_coeff is None: self.converged, self.e_tot, self.mf_elec.mo_energy, \ self.mf_elec.mo_coeff, self.mf_elec.mo_occ = \ kernel(self, self.conv_tol, self.conv_tol_grad, dm0e=dm0e, dm0n=dm0n, callback=self.callback, conv_check=self.conv_check, **kwargs)[0 : 5] else: self.e_tot = kernel(self, self.conv_tol, self.conv_tol_grad, dm0e=dm0e, dm0n=dm0n, callback=self.callback, conv_check=self.conv_check, **kwargs)[1] logger.timer(self, 'SCF', *cput0) self._finalize() return self.e_tot kernel = lib.alias(scf, alias_name='kernel')
class A: def f1(self): return 'a' f2 = lib.alias(f1)
class GradientsMixin(lib.StreamObject): ''' Basic nuclear gradient functions for non-relativistic methods ''' def __init__(self, method): self.verbose = method.verbose self.stdout = method.stdout self.mol = method.mol self.base = method self.max_memory = self.mol.max_memory self.unit = 'au' self.atmlst = None self.de = None self._keys = set(self.__dict__.keys()) def dump_flags(self, verbose=None): log = logger.new_logger(self, verbose) log.info('\n') if hasattr(self.base, 'converged') and not self.base.converged: log.warn('Ground state %s not converged', self.base.__class__.__name__) log.info('******** %s for %s ********', self.__class__, self.base.__class__) if 'ANG' in self.unit.upper(): raise NotImplementedError('unit Eh/Ang is not supported') else: log.info('unit = Eh/Bohr') log.info('max_memory %d MB (current use %d MB)', self.max_memory, lib.current_memory()[0]) return self def get_hcore(self, mol=None): if mol is None: mol = self.mol return get_hcore(mol) hcore_generator = hcore_generator def get_ovlp(self, mol=None): if mol is None: mol = self.mol return get_ovlp(mol) @lib.with_doc(get_jk.__doc__) def get_jk(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() cpu0 = (time.clock(), time.time()) vj, vk = get_jk(mol, dm) logger.timer(self, 'vj and vk', *cpu0) return vj, vk def get_j(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() intor = mol._add_suffix('int2e_ip1') return -_vhf.direct_mapdm(intor, 's2kl', 'lk->s1ij', dm, 3, mol._atm, mol._bas, mol._env) def get_k(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self.base.make_rdm1() intor = mol._add_suffix('int2e_ip1') return -_vhf.direct_mapdm(intor, 's2kl', 'jk->s1il', dm, 3, mol._atm, mol._bas, mol._env) def get_veff(self, mol=None, dm=None): raise NotImplementedError def make_rdm1e(self, mo_energy=None, mo_coeff=None, mo_occ=None): raise NotImplementedError def grad_nuc(self, mol=None, atmlst=None): if mol is None: mol = self.mol return grad_nuc(mol, atmlst) def optimizer(self, solver='geometric'): '''Geometry optimization solver Kwargs: solver (string) : geometry optimization solver, can be "geomeTRIC" (default) or "berny". ''' if solver.lower() == 'geometric': from pyscf.geomopt import geometric_solver return geometric_solver.GeometryOptimizer(self.as_scanner()) elif solver.lower() == 'berny': from pyscf.geomopt import berny_solver return berny_solver.GeometryOptimizer(self.as_scanner()) else: raise RuntimeError('Unknown geometry optimization solver %s' % solver) @lib.with_doc(symmetrize.__doc__) def symmetrize(self, de, atmlst=None): return symmetrize(self.mol, de, atmlst) def grad_elec(self): raise NotImplementedError def extra_force(self, atom_id, envs): '''Hook for extra contributions in analytical gradients. Contributions like the response of auxiliary basis in density fitting method, the grid response in DFT numerical integration can be put in this function. ''' return 0 def kernel(self, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): cput0 = (time.clock(), time.time()) if mo_energy is None: mo_energy = self.base.mo_energy if mo_coeff is None: mo_coeff = self.base.mo_coeff if mo_occ is None: mo_occ = self.base.mo_occ if atmlst is None: atmlst = self.atmlst else: self.atmlst = atmlst if self.verbose >= logger.WARN: self.check_sanity() if self.verbose >= logger.INFO: self.dump_flags() de = self.grad_elec(mo_energy, mo_coeff, mo_occ, atmlst) self.de = de + self.grad_nuc(atmlst=atmlst) if self.mol.symmetry: self.de = self.symmetrize(self.de, atmlst) logger.timer(self, 'SCF gradients', *cput0) self._finalize() return self.de grad = lib.alias(kernel, alias_name='grad') def _finalize(self): if self.verbose >= logger.NOTE: logger.note(self, '--------------- %s gradients ---------------', self.base.__class__.__name__) self._write(self.mol, self.de, self.atmlst) logger.note(self, '----------------------------------------------') _write = _write as_scanner = as_scanner