def _get_vind(self, dm): '''A single shot solvent effects for given density matrix. ''' if not self._intermediates or self.grids.coords is None: self.build() mol = self.mol r_vdw = self._intermediates['r_vdw'] ylm_1sph = self._intermediates['ylm_1sph'] ui = self._intermediates['ui'] Lmat = self._intermediates['Lmat'] A_diele = self._intermediates['A_diele'] A_inf = self._intermediates['A_inf'] cached_pol = self._intermediates['cached_pol'] if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): # spin-traced DM for UHF or ROHF dm = dm[0] + dm[1] phi = ddcosmo.make_phi(self, dm, r_vdw, ui, ylm_1sph) phi = numpy.linalg.solve(A_diele, A_inf.dot(phi.ravel())) Xvec = numpy.linalg.solve(Lmat, phi.ravel()).reshape(mol.natm, -1) psi, vmat = ddcosmo.make_psi_vmat(self, dm, r_vdw, ui, ylm_1sph, cached_pol, Xvec, Lmat)[:2] dielectric = self.eps f_epsilon = (dielectric - 1.) / dielectric epcm = .5 * f_epsilon * numpy.einsum('jx,jx', psi, Xvec) vpcm = .5 * f_epsilon * vmat return epcm, vpcm
def get_phi1(pcmojb): pcmobj.grids.build() mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax r_vdw = pcmobj.get_atomic_radii() coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) ui = 1 - fi ui[ui < 0] = 0 nexposed = numpy.count_nonzero(ui == 1) nbury = numpy.count_nonzero(ui == 0) on_shell = numpy.count_nonzero(ui > 0) - nexposed nlm = (lmax + 1)**2 Lmat = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) Lmat = Lmat.reshape(natm * nlm, -1) cached_pol = ddcosmo.cache_fake_multipoles(pcmobj.grids, r_vdw, lmax) phi = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui, ylm_1sph) L_X = numpy.linalg.solve(Lmat, phi.ravel()).reshape(natm, -1) psi, vmat, L_S = \ ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, ylm_1sph, cached_pol, L_X, Lmat) phi1 = ddcosmo_grad.make_phi1(pcmobj, dm, r_vdw, ui, ylm_1sph) phi1 = numpy.einsum('izjx,jx->iz', phi1, L_S) return L_S, phi, phi1
def _B_dot_x(self, dm): ''' Compute the matrix-vector product B * x. The B matrix, as defined in the paper R. Cammi, JPCA, 104, 5631 (2000), is the second order derivatives of E_solvation wrt density matrices. Note: In ddCOSMO, strictly, B is not symmetric. To make it compatible with the CIS framework, it is symmetrized in current implementation. ''' if not self._intermediates or self.grids.coords is None: self.build() mol = self.mol r_vdw = self._intermediates['r_vdw' ] ylm_1sph = self._intermediates['ylm_1sph' ] ui = self._intermediates['ui' ] Lmat = self._intermediates['Lmat' ] A_diele = self._intermediates['A_diele' ] A_inf = self._intermediates['A_inf' ] cached_pol = self._intermediates['cached_pol'] natm = mol.natm nlm = (self.lmax+1)**2 phi = ddcosmo.make_phi(self, dm, r_vdw, ui, ylm_1sph, with_nuc=False) phi = numpy.linalg.solve(A_diele, A_inf.dot(phi.reshape(-1,natm*nlm).T)) Xvec = numpy.linalg.solve(Lmat, phi) Xvec = Xvec.reshape(natm,nlm,-1).transpose(2,0,1) vmat = ddcosmo.make_psi_vmat(self, dm, r_vdw, ui, ylm_1sph, cached_pol, Xvec, Lmat, with_nuc=False)[1] dielectric = self.eps f_epsilon = (dielectric-1.)/dielectric return .5 * f_epsilon * vmat
def get_phi1(pcmojb): pcmobj.grids.build() mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax r_vdw = pcmobj.get_atomic_radii() coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) ui = 1 - fi ui[ui<0] = 0 nexposed = numpy.count_nonzero(ui==1) nbury = numpy.count_nonzero(ui==0) on_shell = numpy.count_nonzero(ui>0) - nexposed nlm = (lmax+1)**2 Lmat = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) Lmat = Lmat.reshape(natm*nlm,-1) cached_pol = ddcosmo.cache_fake_multipoles(pcmobj.grids, r_vdw, lmax) phi = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui) L_X = numpy.linalg.solve(Lmat, phi.ravel()).reshape(natm,-1) psi, vmat, L_S = \ ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L_X, Lmat) phi1 = ddcosmo_grad.make_phi1(pcmobj, dm, r_vdw, ui) phi1 = numpy.einsum('izjx,jx->iz', phi1, L_S) return L_S, phi, phi1
def gen_vind(dm): phi = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui) phi = numpy.linalg.solve(A_diele, A_inf.dot(phi.ravel())) L_X = numpy.linalg.solve(Lmat, phi.ravel()).reshape(natm, -1) psi, vmat = ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L_X, Lmat)[:2] dielectric = pcmobj.eps f_epsilon = (dielectric - 1.) / dielectric epcm = .5 * f_epsilon * numpy.einsum('jx,jx', psi, L_X) return epcm, .5 * f_epsilon * vmat
def gen_vind(dm): phi = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui) phi = numpy.linalg.solve(A_diele, A_inf.dot(phi.ravel())) L_X = numpy.linalg.solve(Lmat, phi.ravel()).reshape(natm,-1) psi, vmat = ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L_X, Lmat)[:2] dielectric = pcmobj.eps f_epsilon = (dielectric-1.)/dielectric epcm = .5 * f_epsilon * numpy.einsum('jx,jx', psi, L_X) return epcm, .5 * f_epsilon * vmat
def test_B_dot_x(self): pcm = ddcosmo.DDCOSMO(mol) pcm.lmax = 2 pcm.eps = 0 natm = mol.natm nao = mol.nao nlm = (pcm.lmax + 1)**2 r_vdw = ddcosmo.get_atomic_radii(pcm) fi = ddcosmo.make_fi(pcm, r_vdw) ui = 1 - fi ui[ui < 0] = 0 grids = dft.gen_grid.Grids(mol).run(level=0) pcm.grids = grids coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcm.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcm.lmax, True)) cached_pol = ddcosmo.cache_fake_multipoles(grids, r_vdw, pcm.lmax) L = ddcosmo.make_L(pcm, r_vdw, ylm_1sph, fi) B = make_B(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) numpy.random.seed(19) dm = numpy.random.random((2, nao, nao)) Bx = numpy.einsum('ijkl,xkl->xij', B, dm) phi = ddcosmo.make_phi(pcm, dm, r_vdw, ui, ylm_1sph, with_nuc=False) Xvec = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi.reshape(-1, natm * nlm).T) Xvec = Xvec.reshape(natm, nlm, -1).transpose(2, 0, 1) psi, vref, LS = ddcosmo.make_psi_vmat(pcm, dm, r_vdw, ui, ylm_1sph, cached_pol, Xvec, L, with_nuc=False) self.assertAlmostEqual(abs(Bx - vref).max(), 0, 12) e1 = numpy.einsum('nij,nij->n', psi, Xvec) e2 = numpy.einsum('nij,nij->n', phi, LS) e3 = numpy.einsum('nij,nij->n', dm, vref) * .5 self.assertAlmostEqual(abs(e1 - e2).max(), 0, 12) self.assertAlmostEqual(abs(e1 - e3).max(), 0, 12) vmat = pcm._B_dot_x(dm) self.assertEqual(vmat.shape, (2, nao, nao)) self.assertAlmostEqual(abs(vmat - vref * .5).max(), 0, 12) self.assertAlmostEqual(lib.fp(vmat), -17.383712106418606, 12)
def test_phi(self): pcm = ddcosmo.DDCOSMO(mol) r_vdw = ddcosmo.get_atomic_radii(pcm) fi = ddcosmo.make_fi(pcm, r_vdw) ui = 1 - fi ui[ui<0] = 0 numpy.random.seed(1) nao = mol.nao_nr() dm = numpy.random.random((nao,nao)) dm = dm + dm.T v_phi = make_v_phi(mol, dm, r_vdw, pcm.lebedev_order) coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcm.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcm.lmax, True)) phi = -numpy.einsum('n,xn,jn,jn->jx', weights_1sph, ylm_1sph, ui, v_phi) phi1 = ddcosmo.make_phi(pcm, dm, r_vdw, ui) self.assertTrue(abs(phi - phi1).max() < 1e-12)
def kernel(pcmobj, dm, verbose=None): mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax if pcmobj.grids.coords is None: pcmobj.grids.build(with_non0tab=True) if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): # UHF density matrix dm = dm[0] + dm[1] r_vdw = ddcosmo.get_atomic_radii(pcmobj) coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) ui = 1 - fi ui[ui < 0] = 0 cached_pol = ddcosmo.cache_fake_multipoles(pcmobj.grids, r_vdw, lmax) nlm = (lmax + 1)**2 L0 = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) L0 = L0.reshape(natm * nlm, -1) L1 = make_L1(pcmobj, r_vdw, ylm_1sph, fi) phi0 = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui) phi1 = make_phi1(pcmobj, dm, r_vdw, ui) L0_X = numpy.linalg.solve(L0, phi0.ravel()).reshape(natm, -1) psi0, vmat, L0_S = \ ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L0_X, L0) e_psi1 = make_e_psi1(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L0_X, L0) dielectric = pcmobj.eps if dielectric > 0: f_epsilon = (dielectric - 1.) / dielectric else: f_epsilon = 1 de = .5 * f_epsilon * e_psi1 de += .5 * f_epsilon * numpy.einsum('jx,azjx->az', L0_S, phi1) de -= .5 * f_epsilon * numpy.einsum('aziljm,il,jm->az', L1, L0_S, L0_X) return de
def kernel(pcmobj, dm, verbose=None): mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax if pcmobj.grids.coords is None: pcmobj.grids.build(with_non0tab=True) if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): # UHF density matrix dm = dm[0] + dm[1] r_vdw = ddcosmo.get_atomic_radii(pcmobj) coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) ui = 1 - fi ui[ui<0] = 0 cached_pol = ddcosmo.cache_fake_multipoles(pcmobj.grids, r_vdw, lmax) nlm = (lmax+1)**2 L0 = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) L0 = L0.reshape(natm*nlm,-1) L1 = make_L1(pcmobj, r_vdw, ylm_1sph, fi) phi0 = ddcosmo.make_phi(pcmobj, dm, r_vdw, ui) phi1 = make_phi1(pcmobj, dm, r_vdw, ui) L0_X = numpy.linalg.solve(L0, phi0.ravel()).reshape(natm,-1) psi0, vmat, L0_S = \ ddcosmo.make_psi_vmat(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L0_X, L0) e_psi1 = make_e_psi1(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L0_X, L0) dielectric = pcmobj.eps if dielectric > 0: f_epsilon = (dielectric-1.)/dielectric else: f_epsilon = 1 de = .5 * f_epsilon * e_psi1 de+= .5 * f_epsilon * numpy.einsum('jx,azjx->az', L0_S, phi1) de-= .5 * f_epsilon * numpy.einsum('aziljm,il,jm->az', L1, L0_S, L0_X) return de
def test_phi(self): pcm = ddcosmo.DDCOSMO(mol) r_vdw = ddcosmo.get_atomic_radii(pcm) fi = ddcosmo.make_fi(pcm, r_vdw) ui = 1 - fi ui[ui < 0] = 0 numpy.random.seed(1) nao = mol.nao_nr() dm = numpy.random.random((nao, nao)) dm = dm + dm.T v_phi = make_v_phi(mol, dm, r_vdw, pcm.lebedev_order) coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcm.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcm.lmax, True)) phi = -numpy.einsum('n,xn,jn,jn->jx', weights_1sph, ylm_1sph, ui, v_phi) phi1 = ddcosmo.make_phi(pcm, dm, r_vdw, ui, ylm_1sph) self.assertTrue(abs(phi - phi1).max() < 1e-12)