def test_ddcosmo_scf(self): mol = gto.M(atom=''' H 0 0 0 ''', charge=1, basis='sto3g', verbose=7, output='/dev/null') pcm = ddcosmo.DDCOSMO(mol) pcm.lmax = 10 pcm.lebedev_order = 29 mf = ddcosmo.ddcosmo_for_scf(scf.RHF(mol), pcm) mf.init_guess = '1e' mf.run() self.assertAlmostEqual(mf.e_tot, -0.1645636146393864, 9) mol = gto.M(atom=''' 6 0.000000 0.000000 -0.542500 8 0.000000 0.000000 0.677500 1 0.000000 0.935307 -1.082500 1 0.000000 -0.935307 -1.082500 ''', basis='sto3g', verbose=7, output='/dev/null') pcm = ddcosmo.DDCOSMO(mol) pcm.lmax = 6 pcm.lebedev_order = 17 mf = ddcosmo.ddcosmo_for_scf(scf.RHF(mol), pcm).run() self.assertAlmostEqual(mf.e_tot, -112.35450855007909, 9)
def test_e_cosmo_grad(self): pcmobj = ddcosmo.DDCOSMO(mol0) de = ddcosmo_grad.kernel(pcmobj, dm) pcmobj = ddcosmo.DDCOSMO(mol1) e1 = pcmobj.energy(dm) pcmobj = ddcosmo.DDCOSMO(mol2) e2 = pcmobj.energy(dm) self.assertAlmostEqual(abs((e2 - e1) / dx - de[0, 2]).max(), 0, 7)
def ddCOSMO(method_or_mol, solvent_obj=None, dm=None): '''Initialize ddCOSMO model. Examples: >>> mf = ddCOSMO(scf.RHF(mol)) >>> mf.kernel() >>> sol = ddCOSMO(mol) >>> mc = ddCOSMO(CASCI(mf, 6, 6), sol) >>> mc.kernel() ''' from pyscf import gto from pyscf import scf, mcscf from pyscf import tdscf if isinstance(method_or_mol, gto.mole.Mole): return ddcosmo.DDCOSMO(method_or_mol) elif isinstance(method_or_mol, scf.hf.SCF): return ddcosmo.ddcosmo_for_scf(method_or_mol, solvent_obj, dm) elif isinstance(method_or_mol, mcscf.mc1step.CASSCF): return ddcosmo.ddcosmo_for_casscf(method_or_mol, solvent_obj, dm) elif isinstance(method_or_mol, mcscf.casci.CASCI): return ddcosmo.ddcosmo_for_casci(method_or_mol, solvent_obj, dm) elif isinstance(method_or_mol, (tdscf.rhf.TDA, tdscf.rhf.TDHF)): return ddcosmo.ddcosmo_for_tdscf(method_or_mol, solvent_obj, dm) else: return ddcosmo.ddcosmo_for_post_scf(method_or_mol, solvent_obj, dm)
def test_psi_vmat(self): pcm = ddcosmo.DDCOSMO(mol) pcm.lmax = 2 pcm.eps = 0 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() 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) 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, 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.reshape(natm * nlm, -1).T, 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 test_e_psi1(self): def get_e_psi1(pcmobj): pcmobj.grids.build() mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax 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 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) psi1 = ddcosmo_grad.make_e_psi1(pcmobj, dm, r_vdw, ui, pcmobj.grids, ylm_1sph, cached_pol, L_X, Lmat) return L_X, psi, psi1 pcmobj = ddcosmo.DDCOSMO(mol0) L_X, psi0, psi1 = get_e_psi1(pcmobj) pcmobj = ddcosmo.DDCOSMO(mol1) L_X1, psi = get_e_psi1(pcmobj)[:2] e1 = numpy.einsum('jx,jx', psi, L_X) pcmobj = ddcosmo.DDCOSMO(mol2) L_X2, psi = get_e_psi1(pcmobj)[:2] e2 = numpy.einsum('jx,jx', psi, L_X) self.assertAlmostEqual(abs((e2 - e1) / dx - psi1[0, 2]).max(), 0, 7)
def test_L1(self): pcmobj = ddcosmo.DDCOSMO(mol0) 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, pcmobj.lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) L1 = ddcosmo_grad.make_L1(pcmobj, r_vdw, ylm_1sph, fi) pcmobj = ddcosmo.DDCOSMO(mol1) fi = ddcosmo.make_fi(pcmobj, r_vdw) L_1 = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) pcmobj = ddcosmo.DDCOSMO(mol2) fi = ddcosmo.make_fi(pcmobj, r_vdw) L_2 = ddcosmo.make_L(pcmobj, r_vdw, ylm_1sph, fi) self.assertAlmostEqual(abs((L_2-L_1)/dx - L1[0,2]).max(), 0, 7)
def test_solvent_nuc(self): def get_nuc(mol): 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 pcm.grids = grids = dft.gen_grid.Grids(mol).run(level=0) 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) return nuc_part(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) pcm = ddcosmo.DDCOSMO(mol0) pcm.lmax = 2 pcm.eps = 0 natm = mol0.natm nao = mol0.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 pcm.grids = grids = dft.gen_grid.Grids(mol0).run(level=0) 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) dvmat = nuc_part1(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) vmat1 = get_nuc(mol1) vmat2 = get_nuc(mol2) self.assertAlmostEqual( abs((vmat2 - vmat1) / dx - dvmat[0, 2]).max(), 0, 8) nao = mol0.nao numpy.random.seed(19) dm = numpy.random.random((nao, nao)) vref = pcm._get_vind(dm)[1] vmat = 0.5 * get_nuc(mol0) vmat += pcm._B_dot_x(dm) self.assertAlmostEqual(abs(vmat - vref).max(), 0, 14) dm1 = numpy.random.random((2, nao, nao)) de = _ddcosmo_tdscf_grad._grad_ne(pcm, dm1, r_vdw, ui, ylm_1sph, cached_pol, L) ref = numpy.einsum('azij,nij->naz', dvmat, dm1) self.assertAlmostEqual(abs(de - ref).max(), 0, 12)
def test_fi(self): pcmobj = ddcosmo.DDCOSMO(mol0) fi1 = ddcosmo_grad.make_fi1(pcmobj, pcmobj.get_atomic_radii()) ui1 = -fi1 fi = ddcosmo.make_fi(pcmobj, pcmobj.get_atomic_radii()) ui = 1 - fi ui1[:, :, ui < 0] = 0 pcmobj = ddcosmo.DDCOSMO(mol1) fi_1 = ddcosmo.make_fi(pcmobj, pcmobj.get_atomic_radii()) ui_1 = 1 - fi_1 ui_1[ui_1 < 0] = 0 pcmobj = ddcosmo.DDCOSMO(mol2) fi_2 = ddcosmo.make_fi(pcmobj, pcmobj.get_atomic_radii()) ui_2 = 1 - fi_2 ui_2[ui_2 < 0] = 0 self.assertAlmostEqual(abs((fi_2 - fi_1) / dx - fi1[0, 2]).max(), 0, 6) self.assertAlmostEqual(abs((ui_2 - ui_1) / dx - ui1[0, 2]).max(), 0, 6)
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_L_x(self): pcm = ddcosmo.DDCOSMO(mol) r_vdw = ddcosmo.get_atomic_radii(pcm) n = mol.natm * (pcm.lmax + 1)**2 Lref = make_L(pcm, r_vdw, pcm.lebedev_order, pcm.lmax, pcm.eta).reshape(n, n) 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)) fi = ddcosmo.make_fi(pcm, r_vdw) L = ddcosmo.make_L(pcm, r_vdw, ylm_1sph, fi).reshape(n, n) numpy.random.seed(1) x = numpy.random.random(n) self.assertTrue(abs(Lref.dot(n) - L.dot(n)).max() < 1e-12)
def getB(mol): 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 pcm.grids = grids = dft.gen_grid.Grids(mol).run(level=0) 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) return make_B(pcm, r_vdw, ui, ylm_1sph, cached_pol, L)
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)
def ddcosmo_grad(grad_method, pcmobj=None): grad_method_class = grad_method.__class__ class WithSolventGrad(grad_method.__class__): def __init__(self, pcmobj): self.__dict__.update(grad_method.__dict__) self.with_solvent = pcmobj self.de_solvent = None self.de_solute = None self._keys = self._keys.union( ['with_solvent', 'de_solvent', 'de_solute']) def kernel(self, dm=None, atmlst=None): if dm is None: dm = grad_method.base.make_rdm1(ao_repr=True) # de_solvent needs to be called first because _finalize method # is called in the grad_method.kernel function. de_solvent is # required by the _finalize method. self.de_solvent = kernel(self.with_solvent, dm) self.de_solute = grad_method_class.kernel(self, atmlst=atmlst) self.de = self.de_solute + self.de_solvent if self.verbose >= logger.NOTE: logger.note( self, '--------------- %s (%s) gradients ---------------', grad_method.base.__class__.__name__, self.with_solvent.__class__.__name__) rhf_grad._write(self, self.mol, self.de, self.atmlst) logger.note(self, '----------------------------------------------') return self.de def _finalize(self): # disable _finalize. It is called in grad_method.kernel method # where self.de was not yet initialized. pass if pcmobj is None: pcmobj = ddcosmo.DDCOSMO(mf.mol) return WithSolventGrad(pcmobj)
def test_vmat(self): mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1', verbose=0) pcmobj = ddcosmo.DDCOSMO(mol) f = pcmobj.as_solver() nao = mol.nao_nr() numpy.random.seed(1) dm1 = numpy.random.random((nao, nao)) dm1 = dm1 + dm1.T e0, vmat0 = f(dm1) dx = 0.0001 vmat1 = numpy.zeros_like(dm1) for i in range(nao): for j in range(i): dm1[i, j] += dx dm1[j, i] += dx e1 = f(dm1)[0] vmat1[i, j] = vmat1[j, i] = (e1 - e0) / (dx * 2) dm1[i, j] -= dx dm1[j, i] -= dx dm1[i, i] += dx e1 = f(dm1)[0] vmat1[i, i] = (e1 - e0) / dx dm1[i, i] -= dx self.assertAlmostEqual(abs(vmat0 - vmat1).max(), 0, 4)
def test_B1(self): def getB(mol): 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 pcm.grids = grids = dft.gen_grid.Grids(mol).run(level=0) 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) return make_B(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) pcm = ddcosmo.DDCOSMO(mol0) pcm.lmax = 2 pcm.eps = 0 natm = mol0.natm nao = mol0.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 pcm.grids = grids = dft.gen_grid.Grids(mol0).run(level=0) 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) dB = make_B1(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) B1 = getB(mol1) B2 = getB(mol2) self.assertAlmostEqual(abs((B2 - B1) / dx - dB[0, 2]).max(), 0, 8) nao = mol0.nao numpy.random.seed(1) dm1 = numpy.random.random((2, nao, nao)) dm2 = numpy.random.random((2, nao, nao)) dm = dm1[0] ref = numpy.einsum('azpqrs,npq->nazrs', dB, dm1) v = B1_dot_x(pcm, dm, r_vdw, ui, ylm_1sph, cached_pol, L) self.assertAlmostEqual(abs(v - ref[0]).max(), 0, 12) de = _ddcosmo_tdscf_grad._grad_ee(pcm, dm1, dm2, r_vdw, ui, ylm_1sph, cached_pol, L) ref = numpy.einsum('nazij,nij->naz', ref, dm2) self.assertAlmostEqual(abs(de - ref).max(), 0, 12) numpy.random.seed(1) dm = numpy.random.random((nao, nao)) dm = dm + dm.T ref = ddcosmo_grad.kernel(pcm, dm) dielectric = pcm.eps if dielectric > 0: f_epsilon = (dielectric - 1.) / dielectric else: f_epsilon = 1 de = _ddcosmo_tdscf_grad._grad_nn(pcm, r_vdw, ui, ylm_1sph, cached_pol, L) de += _ddcosmo_tdscf_grad._grad_ne(pcm, dm, r_vdw, ui, ylm_1sph, cached_pol, L) de += .5 * _ddcosmo_tdscf_grad._grad_ee(pcm, dm, dm, r_vdw, ui, ylm_1sph, cached_pol, L) de *= .5 * f_epsilon self.assertAlmostEqual(abs(de - ref).max(), 0, 12)