Path: blob/main/chemistry-simulations/aux_files/qmmm/qchem/cppe_lib.py
1165 views
try:1import numpy as np2except ValueError:3print('Numpy should be installed')45#`try:`6#` from pyscf import gto,scf,solvent`7#`except ValueError:`8#` print('PySCF should be installed. Use pip install pyscf')`910try:11import cppe12except ValueError:13print(14'cppe library should be installed to use the polaizable embedding model. Use pip install cppe'15)1617#` The CPPE library can be installed via: pip install cppe`18#` You might need to use (apt-get update & apt-get install build-essential -y`19#` apt-get install python3-dev) before installing cppe.`20####################################212223class PolEmbed:2425def __init__(self, mol, peoptions):2627self.mol = mol2829if isinstance(peoptions, str):30options = {"potfile": peoptions}31else:32options = peoptions3334if not isinstance(options, dict):35raise TypeError("Options should be a dictionary.")3637self.options = options38self.cppe_state = self._cppe_state(mol)39self.potentials = self.cppe_state.potentials40self.polarizable_coords = np.array([41site.position42for site in self.cppe_state.potentials43if site.is_polarizable44])4546self.V_es = None4748def _cppe_state(self, mol):4950cppe_mol = cppe.Molecule()51for z, coord in zip(mol.atom_charges(), mol.atom_coords()):52cppe_mol.append(cppe.Atom(z, *coord))5354cppe_state = cppe.CppeState(self.options, cppe_mol)55cppe_state.calculate_static_energies_and_fields()5657return cppe_state5859def _compute_field_integrals(self, site, moment):60self.mol.set_rinv_orig(site)61integral = self.mol.intor("int1e_iprinv") + self.mol.intor(62"int1e_iprinv").transpose(0, 2, 1)63op = np.einsum('aij,a->ij', integral, -1.0 * moment)6465return op6667def _compute_field(self, site, dm):6869self.mol.set_rinv_orig(site)70integral = self.mol.intor("int1e_iprinv") + self.mol.intor(71"int1e_iprinv").transpose(0, 2, 1)7273return np.einsum('ij,aij->a', dm, integral)7475def _compute_multipole_potential_integrals(self, site, order, moments):7677if order > 2:78raise NotImplementedError(79"""Multipole potential integrals not implemented for order > 2."""80)8182self.mol.set_rinv_orig(site)8384# Order 0:85#if order==0:86integral0 = self.mol.intor("int1e_rinv")87es_operator = integral0 * moments[0] * cppe.prefactors(0)8889# Order 1:90if order > 0:91integral1 = self.mol.intor("int1e_iprinv") + self.mol.intor(92"int1e_iprinv").transpose(0, 2, 1)93es_operator += np.einsum('aij,a->ij', integral1,94moments[1] * cppe.prefactors(1))9596# Order 2:97if order > 1:98integral2 = self.mol.intor("int1e_ipiprinv") + self.mol.intor("int1e_ipiprinv").transpose(0, 2, 1) \99+ 2.0 * self.mol.intor("int1e_iprinvip")100# add the lower triangle to the upper triangle101integral2[1] += integral2[3]102integral2[2] += integral2[6]103integral2[5] += integral2[7]104integral2[1] *= 0.5105integral2[2] *= 0.5106integral2[5] *= 0.5107108es_operator += np.einsum('aij,a->ij',109integral2[[0, 1, 2, 4, 5, 8], :, :],110moments[2] * cppe.prefactors(2))111112return es_operator113114def get_pe_contribution(self, dm, elec_only=False):115116# Step I: Build electrostatic operator117if self.V_es is None:118self.V_es = np.zeros((self.mol.nao, self.mol.nao), dtype=np.float64)119for p in self.potentials:120moments = []121for m in p.multipoles:122m.remove_trace()123moments.append(m.values)124self.V_es += self._compute_multipole_potential_integrals(125p.position, m.k, moments)126127e_static = np.einsum('ij,ij->', self.V_es, dm)128self.cppe_state.energies["Electrostatic"]["Electronic"] = e_static129130#` Step II: obtain expectation values of elec. field at polarizable sites`131n_sitecoords = 3 * self.cppe_state.get_polarizable_site_number()132V_ind = np.zeros((self.mol.nao, self.mol.nao), dtype=np.float64)133if n_sitecoords:134current_polsite = 0135elec_fields = np.zeros(n_sitecoords, dtype=np.float64)136for p in self.potentials:137if not p.is_polarizable:138continue139elec_fields_s = self._compute_field(p.position, dm)140elec_fields[3 * current_polsite:3 * current_polsite +1413] = elec_fields_s142current_polsite += 1143144# Step III: solve induced moments145self.cppe_state.update_induced_moments(elec_fields, elec_only)146induced_moments = np.array(self.cppe_state.get_induced_moments())147148# Step IV: build induction operator149current_polsite = 0150for p in self.potentials:151if not p.is_polarizable:152continue153site = p.position154V_ind += self._compute_field_integrals(155site=site,156moment=induced_moments[3 *157current_polsite:3 * current_polsite +1583])159current_polsite += 1160161E_pe = self.cppe_state.total_energy162163if not elec_only:164V_pe = self.V_es + V_ind165else:166V_pe = V_ind167E_pe = self.cppe_state.energies["Polarization"]["Electronic"]168169return E_pe, V_pe, self.V_es, V_ind170171172