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 B1_dot_x(pcmobj, dm, r_vdw, ui, ylm_1sph, cached_pol, L): mol = pcmobj.mol mol = pcmobj.mol natm = mol.natm nao = mol.nao lmax = pcmobj.lmax nlm = (lmax + 1)**2 dms = numpy.asarray(dm) is_single_dm = dms.ndim == 2 dms = dms.reshape(-1, nao, nao) n_dm = dms.shape[0] atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() aoslices = mol.aoslice_by_atom() grids = pcmobj.grids coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] extern_point_idx = ui > 0 fi0 = ddcosmo.make_fi(pcmobj, r_vdw) fi1 = ddcosmo_grad.make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:, :, ui == 0] = 0 ui1 = -fi1 Bx = numpy.zeros((natm, 3, nao, nao)) ao = mol.eval_gto('GTOval', grids.coords) aow = numpy.einsum('gi,g->gi', ao, grids.weights) aopair = numpy.einsum('gi,gj->gij', ao, aow) den = numpy.einsum('gij,ij->g', aopair, dm) psi0 = numpy.zeros((natm, nlm)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] fac_pol = ddcosmo._vstack_factor_fak_pol(fak_pol, lmax) i0, i1 = i1, i1 + fac_pol.shape[1] psi0[ia] = -numpy.einsum('mn,n->m', fac_pol, den[i0:i1]) LS0 = numpy.linalg.solve(L.reshape(natm * nlm, -1).T, psi0.ravel()) LS0 = LS0.reshape(natm, nlm) phi0 = numpy.zeros((natm, nlm)) phi1 = numpy.zeros((natm, 3, natm, nlm)) int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) cintopt_ip1 = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e_ip1) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) v_phi = numpy.einsum('pqg,pq->g', v_nj, dm) phi0[ia] = numpy.einsum('n,ln,n,n->l', weights_1sph, ylm_1sph, ui[ia], v_phi) phi1[:, :, ia] += lib.einsum('n,ln,azn,n->azl', weights_1sph, ylm_1sph, ui1[:, :, ia], v_phi) Bx += lib.einsum('l,n,ln,azn,ijn->azij', LS0[ia], weights_1sph, ylm_1sph, ui1[:, :, ia], v_nj) wtmp = lib.einsum('n,ln,n->ln', weights_1sph, ylm_1sph, ui[ia]) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1', cintopt=cintopt_ip1) vtmp = lib.einsum('l,ln,xijn->xij', LS0[ia], wtmp, v_e1_nj) Bx[ia] += vtmp Bx[ia] += vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] Bx[ja, :, p0:p1, :] -= vtmp[:, p0:p1] Bx[ja, :, :, p0:p1] -= vtmp[:, p0:p1].transpose(0, 2, 1) tmp = numpy.einsum('xijn,ij->xn', v_e1_nj[:, p0:p1], dm[p0:p1]) tmp += numpy.einsum('xijn,ji->xn', v_e1_nj[:, p0:p1], dm[:, p0:p1]) phitmp = numpy.einsum('ln,xn->xl', wtmp, tmp) phi1[ja, :, ia] -= phitmp phi1[ia, :, ia] += phitmp Xvec0 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi0.ravel()) Xvec0 = Xvec0.reshape(natm, nlm) L1 = ddcosmo_grad.make_L1(pcmobj, r_vdw, ylm_1sph, fi0) phi1 -= lib.einsum('aziljm,jm->azil', L1, Xvec0) Xvec1 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi1.reshape(-1, natm * nlm).T) Xvec1 = Xvec1.T.reshape(natm, 3, natm, nlm) psi1 = numpy.zeros((natm, 3, natm, nlm)) i1 = 0 for ia, (coords, weight, weight1) in enumerate(rks_grad.grids_response_cc(grids)): i0, i1 = i1, i1 + weight.size ao = mol.eval_gto('GTOval_sph_deriv1', coords) aow = numpy.einsum('gi,g->gi', ao[0], weight) aopair1 = lib.einsum('xgi,gj->xgij', ao[1:], aow) aow = numpy.einsum('gi,zxg->zxgi', ao[0], weight1) aopair0 = lib.einsum('zxgi,gj->zxgij', aow, ao[0]) den0 = numpy.einsum('zxgij,ij->zxg', aopair0, dm) den1 = numpy.empty((natm, 3, weight.size)) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] den1[ja] = numpy.einsum('xgij,ij->xg', aopair1[:, :, p0:p1], dm[p0:p1, :]) den1[ja] += numpy.einsum('xgij,ji->xg', aopair1[:, :, p0:p1], dm[:, p0:p1]) fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] fac_pol = ddcosmo._vstack_factor_fak_pol(fak_pol, lmax) scaled_weights = lib.einsum('azm,mn->azn', Xvec1[:, :, ia], fac_pol) scaled_weights *= weight aow = numpy.einsum('gi,azg->azgi', ao[0], scaled_weights) Bx -= numpy.einsum('gi,azgj->azij', ao[0], aow) tmp = numpy.einsum('mn,zxn->zxm', fac_pol, den1) psi1[:, :, ia] -= numpy.einsum('mn,zxn->zxm', fac_pol, den0) psi1[ia, :, ia] -= tmp.sum(axis=0) for ja in range(natm): psi1[ja, :, ia] += tmp[ja] eta_nj = lib.einsum('mn,m->n', fac_pol, Xvec0[ia]) Bx -= lib.einsum('n,zxnpq->zxpq', eta_nj, aopair0) vtmp = lib.einsum('n,xnpq->xpq', eta_nj, aopair1) Bx[ia] -= vtmp Bx[ia] -= vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, q0, q1 = aoslices[ja] Bx[ja, :, q0:q1, :] += vtmp[:, q0:q1] Bx[ja, :, :, q0:q1] += vtmp[:, q0:q1].transpose(0, 2, 1) psi1 -= numpy.einsum('il,aziljm->azjm', LS0, L1) LS1 = numpy.linalg.solve( L.reshape(natm * nlm, -1).T, psi1.reshape(-1, natm * nlm).T) LS1 = LS1.T.reshape(natm, 3, natm, nlm) cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) v_phi = numpy.zeros((natm, ngrid_1sph, nao, nao)) v_phi[extern_point_idx] += v_nj.transpose(2, 0, 1) Bx += lib.einsum('azjx,n,xn,jn,jnpq->azpq', LS1, weights_1sph, ylm_1sph, ui, v_phi) return Bx
def make_B1(pcmobj, r_vdw, ui, ylm_1sph, cached_pol, L): '''1st order''' mol = pcmobj.mol coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] mol = pcmobj.mol natm = mol.natm nao = mol.nao lmax = pcmobj.lmax nlm = (lmax + 1)**2 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() grids = pcmobj.grids extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] int3c2e = mol._add_suffix('int3c2e') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) nao_pair = v_nj.shape[0] v_phi = numpy.zeros((natm, ngrid_1sph, nao, nao)) v_phi[extern_point_idx] += v_nj.transpose(2, 0, 1) phi0 = numpy.einsum('n,xn,jn,jnpq->jxpq', weights_1sph, ylm_1sph, ui, v_phi) Xvec0 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi0.reshape(natm * nlm, -1)) Xvec0 = Xvec0.reshape(natm, nlm, nao, nao) ao = mol.eval_gto('GTOval', grids.coords) aow = numpy.einsum('gi,g->gi', ao, grids.weights) aopair = numpy.einsum('gi,gj->gij', ao, aow) psi0 = numpy.zeros((natm, nlm, nao, nao)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) psi0[ia, p0:p1] = -fac * numpy.einsum('mn,nij->mij', fak_pol[l], aopair[i0:i1]) fi0 = ddcosmo.make_fi(pcmobj, r_vdw) fi1 = ddcosmo_grad.make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:, :, ui == 0] = 0 ui1 = -fi1 phi1 = numpy.zeros(ui1.shape[:3] + (nlm, nao, nao)) int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') aoslices = mol.aoslice_by_atom() for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1') phi1[:, :, ia] += lib.einsum('n,ln,azn,ijn->azlij', weights_1sph, ylm_1sph, ui1[:, :, ia], v_nj) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1') v_e2_nj = v_e1_nj + v_e1_nj.transpose(0, 2, 1, 3) phi1[ia, :, ia] += lib.einsum('n,ln,n,xijn->xlij', weights_1sph, ylm_1sph, ui[ia], v_e2_nj) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] v = numpy.einsum('n,ln,n,xijn->xlij', weights_1sph, ylm_1sph, ui[ia], v_e1_nj[:, p0:p1]) phi1[ja, :, ia, :, p0:p1, :] -= v phi1[ja, :, ia, :, :, p0:p1] -= v.transpose(0, 1, 3, 2) psi1 = numpy.zeros((natm, 3, natm, nlm, nao, nao)) i1 = 0 for ia, (coords, weight, weight1) in enumerate(rks_grad.grids_response_cc(grids)): i0, i1 = i1, i1 + weight.size ao = mol.eval_gto('GTOval_sph_deriv1', coords) aow = numpy.einsum('gi,g->gi', ao[0], weight) aopair1 = lib.einsum('xgi,gj->xgij', ao[1:], aow) aow = numpy.einsum('gi,zxg->zxgi', ao[0], weight1) aopair0 = lib.einsum('zxgi,gj->zxgij', aow, ao[0]) fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) psi1[:, :, ia, p0:p1] -= fac * numpy.einsum( 'mn,zxnij->zxmij', fak_pol[l], aopair0) vtmp = fac * numpy.einsum('mn,xnij->xmij', fak_pol[l], aopair1) psi1[ia, :, ia, p0:p1] -= vtmp psi1[ia, :, ia, p0:p1] -= vtmp.transpose(0, 1, 3, 2) for ja in range(natm): shl0, shl1, q0, q1 = aoslices[ja] psi1[ja, :, ia, p0:p1, q0:q1, :] += vtmp[:, :, q0:q1] psi1[ja, :, ia, p0:p1, :, q0:q1] += vtmp[:, :, q0:q1].transpose(0, 1, 3, 2) L1 = ddcosmo_grad.make_L1(pcmobj, r_vdw, ylm_1sph, fi0) Xvec1 = numpy.linalg.solve( L.reshape(natm * nlm, -1), phi1.transpose(2, 3, 0, 1, 4, 5).reshape(natm * nlm, -1)) Xvec1 = Xvec1.reshape(natm, nlm, natm, 3, nao, nao).transpose(2, 3, 0, 1, 4, 5) LS0 = numpy.linalg.solve( L.reshape(natm * nlm, -1).T, psi0.reshape(natm * nlm, -1)) LS0 = LS0.reshape(natm, nlm, nao, nao) B = lib.einsum('ixnlpq,nlrs->ixpqrs', psi1, Xvec0) B += lib.einsum('nlpq,ixnlrs->ixpqrs', psi0, Xvec1) B -= lib.einsum('ilpq,aziljm,jmrs->azpqrs', LS0, L1, Xvec0) B = B + B.transpose(0, 1, 4, 5, 2, 3) return B
def nuc_part1(pcmobj, r_vdw, ui, ylm_1sph, cached_pol, L): '''1st order''' mol = pcmobj.mol natm = mol.natm coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] lmax = pcmobj.lmax nlm = (lmax + 1)**2 nao = mol.nao atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() grids = pcmobj.grids aoslices = mol.aoslice_by_atom() extern_point_idx = ui > 0 fi0 = ddcosmo.make_fi(pcmobj, r_vdw) fi1 = ddcosmo_grad.make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:, :, ui == 0] = 0 ui1 = -fi1 vmat1 = numpy.zeros((natm, 3, nao, nao)) cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) v_phi = numpy.zeros((natm, ngrid_1sph)) for ia in range(natm): # Note (-) sign is not applied to atom_charges, because (-) is explicitly # included in rhs and L matrix d_rs = atom_coords.reshape(-1, 1, 3) - cav_coords[ia] v_phi[ia] = numpy.einsum('z,zp->p', atom_charges, 1. / lib.norm(d_rs, axis=2)) phi0 = -numpy.einsum('n,xn,jn,jn->jx', weights_1sph, ylm_1sph, ui, v_phi) Xvec0 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi0.ravel()) Xvec0 = Xvec0.reshape(natm, nlm) ngrid_1sph = weights_1sph.size v_phi0 = numpy.empty((natm, ngrid_1sph)) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph d_rs = atom_coords.reshape(-1, 1, 3) - cav_coords v_phi0[ia] = numpy.einsum('z,zp->p', atom_charges, 1. / lib.norm(d_rs, axis=2)) phi1 = -numpy.einsum('n,ln,azjn,jn->azjl', weights_1sph, ylm_1sph, ui1, v_phi0) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph for ja in range(natm): rs = atom_coords[ja] - cav_coords d_rs = lib.norm(rs, axis=1) v_phi = atom_charges[ja] * numpy.einsum('px,p->px', rs, 1. / d_rs**3) tmp = numpy.einsum('n,ln,n,nx->xl', weights_1sph, ylm_1sph, ui[ia], v_phi) phi1[ja, :, ia] += tmp # response of the other atoms phi1[ia, :, ia] -= tmp # response of cavity grids L1 = ddcosmo_grad.make_L1(pcmobj, r_vdw, ylm_1sph, fi0) phi1 -= lib.einsum('aziljm,jm->azil', L1, Xvec0) Xvec1 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi1.reshape(-1, natm * nlm).T) Xvec1 = Xvec1.T.reshape(natm, 3, natm, nlm) i1 = 0 for ia, (coords, weight, weight1) in enumerate(rks_grad.grids_response_cc(grids)): i0, i1 = i1, i1 + weight.size ao = mol.eval_gto('GTOval_sph_deriv1', coords) aow = numpy.einsum('gi,g->gi', ao[0], weight) aopair1 = lib.einsum('xgi,gj->xgij', ao[1:], aow) aow = numpy.einsum('gi,zxg->zxgi', ao[0], weight1) aopair0 = lib.einsum('zxgi,gj->zxgij', aow, ao[0]) fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] fac_pol = ddcosmo._vstack_factor_fak_pol(fak_pol, lmax) vmat1 -= numpy.einsum('m,mn,zxnij->zxij', Xvec0[ia], fac_pol, aopair0) vtmp = numpy.einsum('m,mn,xnij->xij', Xvec0[ia], fac_pol, aopair1) vmat1[ia, :] -= vtmp vmat1[ia, :] -= vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] vmat1[ja, :, p0:p1, :] += vtmp[:, p0:p1] vmat1[ja, :, :, p0:p1] += vtmp[:, p0:p1].transpose(0, 2, 1) scaled_weights = lib.einsum('azm,mn->azn', Xvec1[:, :, ia], fac_pol) scaled_weights *= weight aow = numpy.einsum('gi,azg->azgi', ao[0], scaled_weights) vmat1 -= numpy.einsum('gi,azgj->azij', ao[0], aow) psi0 = numpy.zeros((natm, nlm)) for ia in range(natm): psi0[ia, 0] += numpy.sqrt(4 * numpy.pi) / r_vdw[ia] * mol.atom_charge(ia) LS0 = numpy.linalg.solve(L.reshape(natm * nlm, -1).T, psi0.ravel()) LS0 = LS0.reshape(natm, nlm) LS1 = numpy.einsum('il,aziljm->azjm', LS0, L1) LS1 = numpy.linalg.solve( L.reshape(natm * nlm, -1).T, LS1.reshape(-1, natm * nlm).T) LS1 = LS1.T.reshape(natm, 3, natm, nlm) int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) wtmp = lib.einsum('l,n,ln->ln', LS0[ia], weights_1sph, ylm_1sph) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) vmat1 -= numpy.einsum('azl,n,ln,n,pqn->azpq', LS1[:, :, ia], weights_1sph, ylm_1sph, ui[ia], v_nj) vmat1 += lib.einsum('ln,azn,ijn->azij', wtmp, ui1[:, :, ia], v_nj) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1') vtmp = lib.einsum('ln,n,xijn->xij', wtmp, ui[ia], v_e1_nj) vmat1[ia] += vtmp vmat1[ia] += vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] vmat1[ja, :, p0:p1, :] -= vtmp[:, p0:p1] vmat1[ja, :, :, p0:p1] -= vtmp[:, p0:p1].transpose(0, 2, 1) return vmat1