def test_psi_vmat(self): pcm = ddcosmo.DDCOSMO(mol) pcm.lmax = 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).build() 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) numpy.random.seed(1) nao = mol.nao_nr() dm = numpy.random.random((nao, nao)) dm = dm + dm.T natm = mol.natm nlm = (pcm.lmax + 1)**2 LX = numpy.random.random((natm, nlm)) L = ddcosmo.make_L(pcm, r_vdw, ylm_1sph, fi) psi, vmat = ddcosmo.make_psi_vmat(pcm, dm, r_vdw, ui, grids, ylm_1sph, cached_pol, LX, L)[:2] psi_ref = make_psi(pcm.mol, dm, r_vdw, pcm.lmax) self.assertAlmostEqual(abs(psi_ref - psi).max(), 0, 12) LS = numpy.linalg.solve(L.T.reshape(natm * nlm, -1), psi_ref.ravel()).reshape(natm, nlm) vmat_ref = make_vmat(pcm, r_vdw, pcm.lebedev_order, pcm.lmax, LX, LS) self.assertAlmostEqual(abs(vmat_ref - vmat).max(), 0, 12)
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 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 _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