Source code for pyscf.pbc.tdscf.rhf

#!/usr/bin/env python
# Copyright 2014-2018 The PySCF Developers. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Qiming Sun <osirpt.sun@gmail.com>
#
# Ref:
# Chem Phys Lett, 256, 454
# J. Mol. Struct. THEOCHEM, 914, 3
#

import numpy as np
from pyscf import lib
from pyscf.tdscf import rhf
from pyscf.pbc import scf
from pyscf import __config__

[docs] def get_ab(mf): r'''A and B matrices for TDDFT response function. A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj) B[i,a,j,b] = (ia||jb) Ref: Chem Phys Lett, 256, 454 ''' cell = mf.cell mo_energy = scf.addons.mo_energy_with_exxdiv_none(mf) mo = np.asarray(mf.mo_coeff) mo_occ = np.asarray(mf.mo_occ) kpt = mf.kpt nao, nmo = mo.shape nocc = np.count_nonzero(mo_occ==2) nvir = nmo - nocc orbo = mo[:,:nocc] orbv = mo[:,nocc:] e_ia = mo_energy[nocc:] - mo_energy[:nocc,None] a = np.diag(e_ia.ravel()).reshape(nocc,nvir,nocc,nvir).astype(mo.dtype) b = np.zeros_like(a) def add_hf_(a, b, hyb=1): eri = mf.with_df.ao2mo([orbo,mo,mo,mo], kpt, compact=False) eri = eri.reshape(nocc,nmo,nmo,nmo) a += np.einsum('iabj->iajb', eri[:nocc,nocc:,nocc:,:nocc]) * 2 a -= np.einsum('ijba->iajb', eri[:nocc,:nocc,nocc:,nocc:]) * hyb b += np.einsum('iajb->iajb', eri[:nocc,nocc:,:nocc,nocc:]) * 2 b -= np.einsum('ibja->iajb', eri[:nocc,nocc:,:nocc,nocc:]) * hyb if isinstance(mf, scf.hf.KohnShamDFT): ni = mf._numint omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, cell.spin) add_hf_(a, b, hyb) if omega != 0: # For RSH raise NotImplementedError xctype = ni._xc_type(mf.xc) dm0 = mf.make_rdm1(mo, mo_occ) make_rho = ni._gen_rho_evaluator(cell, dm0, hermi=1, with_lapl=False)[0] mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory*.8-mem_now) if xctype == 'LDA': ao_deriv = 0 for ao, _, mask, weight, coords \ in ni.block_loop(cell, mf.grids, nao, ao_deriv, kpt, None, max_memory): rho = make_rho(0, ao, mask, xctype) fxc = ni.eval_xc_eff(mf.xc, rho, deriv=2, xctype=xctype)[2] wfxc = fxc[0,0] * weight rho_o = lib.einsum('rp,pi->ri', ao, orbo) rho_v = lib.einsum('rp,pi->ri', ao, orbv) rho_ov = np.einsum('ri,ra->ria', rho_o, rho_v) w_ov = np.einsum('ria,r->ria', rho_ov, wfxc) * 2 rho_vo = rho_ov.conj() a += lib.einsum('ria,rjb->iajb', w_ov, rho_vo) b += lib.einsum('ria,rjb->iajb', w_ov, rho_ov) elif xctype == 'GGA': ao_deriv = 1 for ao, _, mask, weight, coords \ in ni.block_loop(cell, mf.grids, nao, ao_deriv, kpt, None, max_memory): rho = make_rho(0, ao, mask, xctype) fxc = ni.eval_xc_eff(mf.xc, rho, deriv=2, xctype=xctype)[2] wfxc = fxc * weight rho_o = lib.einsum('xrp,pi->xri', ao, orbo) rho_v = lib.einsum('xrp,pi->xri', ao, orbv) rho_ov = np.einsum('xri,ra->xria', rho_o, rho_v[0]) rho_ov[1:4] += np.einsum('ri,xra->xria', rho_o[0], rho_v[1:4]) w_ov = np.einsum('xyr,xria->yria', wfxc, rho_ov) * 2 rho_vo = rho_ov.conj() a += lib.einsum('xria,xrjb->iajb', w_ov, rho_vo) b += lib.einsum('xria,xrjb->iajb', w_ov, rho_ov) elif xctype == 'HF': pass elif xctype == 'NLC': raise NotImplementedError('NLC') elif xctype == 'MGGA': ao_deriv = 1 for ao, _, mask, weight, coords \ in ni.block_loop(cell, mf.grids, nao, ao_deriv, kpt, None, max_memory): rho = make_rho(0, ao, mask, xctype) fxc = ni.eval_xc_eff(mf.xc, rho, deriv=2, xctype=xctype)[2] wfxc = fxc * weight rho_o = lib.einsum('xrp,pi->xri', ao, orbo) rho_v = lib.einsum('xrp,pi->xri', ao, orbv) rho_ov = np.einsum('xri,ra->xria', rho_o, rho_v[0]) rho_ov[1:4] += np.einsum('ri,xra->xria', rho_o[0], rho_v[1:4]) tau_ov = np.einsum('xri,xra->ria', rho_o[1:4], rho_v[1:4]) * .5 rho_ov = np.vstack([rho_ov, tau_ov[np.newaxis]]) w_ov = np.einsum('xyr,xria->yria', wfxc, rho_ov) * 2 rho_vo = rho_ov.conj() a += lib.einsum('xria,xrjb->iajb', w_ov, rho_vo) b += lib.einsum('xria,xrjb->iajb', w_ov, rho_ov) else: add_hf_(a, b) return a, b
[docs] class TDBase(rhf.TDBase): _keys = {'cell'} def __init__(self, mf): rhf.TDBase.__init__(self, mf) self.cell = mf.cell
[docs] def get_ab(self, mf=None): if mf is None: mf = self._scf return get_ab(mf)
[docs] def nuc_grad_method(self): raise NotImplementedError
get_nto = rhf.TDBase.get_nto analyze = lib.invalid_method('analyze') oscillator_strength = lib.invalid_method('oscillator_strength') transition_dipole = lib.invalid_method('transition_dipole') transition_quadrupole = lib.invalid_method('transition_quadrupole') transition_octupole = lib.invalid_method('transition_octupole') transition_velocity_dipole = lib.invalid_method('transition_velocity_dipole') transition_velocity_quadrupole = lib.invalid_method('transition_velocity_quadrupole') transition_velocity_octupole = lib.invalid_method('transition_velocity_octupole') transition_magnetic_dipole = lib.invalid_method('transition_magnetic_dipole') transition_magnetic_quadrupole = lib.invalid_method('transition_magnetic_quadrupole')
[docs] class TDA(TDBase): init_guess = rhf.TDA.init_guess kernel = rhf.TDA.kernel _gen_vind = rhf.TDA.gen_vind
[docs] def gen_vind(self, mf=None): if mf is None: mf = self._scf moe = scf.addons.mo_energy_with_exxdiv_none(mf) with lib.temporary_env(mf, mo_energy=moe): vind, hdiag = self._gen_vind(mf) def vindp(x): with lib.temporary_env(mf, exxdiv=None): return vind(x) return vindp, hdiag
CIS = TDA
[docs] class TDHF(TDBase): init_guess = rhf.TDHF.init_guess kernel = rhf.TDHF.kernel _gen_vind = rhf.TDHF.gen_vind gen_vind = TDA.gen_vind
RPA = TDRHF = TDHF scf.hf.RHF.TDA = lib.class_as_method(TDA) scf.hf.RHF.TDHF = lib.class_as_method(TDHF) scf.rohf.ROHF.TDA = None scf.rohf.ROHF.TDHF = None