c
C> \brief calculate the gradient terms due to the interaction with the
C> COSMO charges
C>
C> Evaluate the gradient contributions from the COSMO embedding. The
C> original part is from Klamt and Schüürmann [1]
C> (see Eqs.(13-16)). The derivatives of matrix \f$A\f$ have been
C> modified by York and Karplus [2] (see Eqs.(73-76)) to obtain smooth
C> potential energy surfaces. York and Karplus also modified matrix
C> \f$B\f$ which is easy to do in their classical force field code.
C> In an ab-initio code this not so easy to do and as it is not
C> required to eliminate singularities the original expression from [1]
C> for \f$B\f$ is used here.
C>
C> ### References ###
C>
C> [1] A. Klamt, G. Schüürmann,
C> "COSMO: a new approach to dielectric screening in solvents with
C> explicit expressions for the screening energy and its gradient",
C> J. Chem. Soc., Perkin Trans. 2, 1993, pp 799-805, DOI:
C>
C> 10.1039/P29930000799.
C>
C> [2] D.M. York, M. Karplus,
C> "A smooth solvation potential based on the conductor-like
C> screening model", J. Phys. Chem. A (1999) 103,
C> pp 11060-11079, DOI:
C>
C> 10.1021/jp992097l.
C>
subroutine grad_hnd_cos ( H, lbuf, scr, lscr,
$ dens, frc_cos_nucq, frc_cos_elq,
$ frc_cos_qq,
$ g_dens, basis, geom, nproc, nat,
$ max_at_bf, rtdb, oskel )
c$Id: grad1.F 27488 2015-09-10 08:44:11Z alogsdail $
C COSMO one electron contribution to RHF, ROHF and UHF gradients
C now also UMP2 ??? unlikely as that requires solutions to the
c CPHF equation???
c
c Terms included in this subroutine are:
c 1. Electron - COSMO charge interactions
c 2. Nuclear - COSMO charge interactions
c 3. COSMO charge - COSMO charge interactions
c
c Terms NOT included are:
c 1. All regular QM derivatives
implicit none
#include "nwc_const.fh"
#include "mafdecls.fh"
#include "errquit.fh"
#include "global.fh"
#include "cosmoP.fh"
#include "cosmo_params.fh"
#include "geomP.fh"
#include "geom.fh"
#include "bq.fh"
#include "bas.fh"
#include "rtdb.fh"
#include "sym.fh"
#include "stdio.fh"
#include "prop.fh"
C-------------------------parameters--------------------------------
integer g_dens !< [Input] the total electron density matrix GA
integer basis !< [Input] the basis set handle
integer geom !< [Input] the geometry handle
integer rtdb !< [Input] the RTDB handle
integer lbuf !< [Input] the length of the integral buffer
integer lscr, !< [Input] the length of the scratch space
$ nproc, nat, max_at_bf
double precision frc_cos_nucq(3,nat) !< [Output] the forces due
!< nuclear-COSMO charge
!< interaction
double precision frc_cos_elq(3,nat) !< [Output] the forces due
!< electron-COSMO charge
!< interaction
double precision frc_cos_qq(3,nat) !< [Output] the forces due
!< COSMO charge-COSMO charge
!< interaction
double precision H(lbuf) !< [Scratch] the derivative integrals
double precision scr(lscr) !< [Scratch] scratch space
double precision dens(max_at_bf,max_at_bf) !< [Scratch] local
!< density block
logical oskel ! symmetry?
c
C-------------------------local variables--------------------------
integer ijatom, next, iat1, iat2, iat3, ish1, ish2,
$ iab1f, iab1l, iab2f, iab2l, iac1f, iac1l, iac2f, iac2l,
$ if1, il1, if2, il2,
$ icart, ic, nint, ip1, ip2
integer im1, im2, nprim, ngen, sphcart, ityp1, ityp2
integer ich1, ich2
integer nefc ! the number of COSMO charges
integer l_efciat ! the handle of the COSMO charge-atom map
integer k_efciat ! the index of the COSMO charge-atom map
integer l_rad ! the handle of the atom radii
integer k_rad ! the index of the atom radii
integer nefcl ! the number of COSMO charge for a given atom
integer iefc ! counter over COSMO charges
integer iefc_c ! memory index for COSMO charge coordinates
integer iefc_q ! memory index for COSMO charges
double precision dE, qfac, fact, dx, dy, dz, rr
double precision invscreen, bohr, pi
double precision zeta1, zeta2, zeta12
parameter (bohr=0.529177249d0)
logical status, pointforce
double precision util_erf, cosff, cosdff
external util_erf, cosff, cosdff
integer nxtask, task_size
external nxtask
c
double precision rin, rout, alphai, xyzff
integer iat
parameter (alphai = 0.5d0)
rin(iat)=dbl_mb(k_rad-1+iat)
& *(1.0d0-alphai*gammas*sqrt(0.25d0**minbem))
rout(iat)=dbl_mb(k_rad-1+iat)
& *(1.0d0+(1.0d0-alphai)*gammas*sqrt(0.25d0**minbem))
c ---- -cosmo- gradient term -----
logical odbug
pi = acos(-1.0d0)
odbug=.false.
if(odbug) then
write(Luout,*) 'in -grad1_hnd_cos- ...'
endif
c
task_size = 1
status = rtdb_parallel(.true.) ! Broadcast reads to all processes
c
pointforce = geom_include_bqbq(geom)
if (.not.bq_create('cosmo efc bq',cosmo_bq_efc))
$ call errquit("grad_hnd_cos: bq_create on cosmo failed",
$ 0,GEOM_ERR)
if (.not.bq_rtdb_load(rtdb,cosmo_bq_efc))
$ call errquit('grad_hnd_cos: rtdb load failed for Bq',916,
$ rtdb_err)
if (.not.bq_ncenter(cosmo_bq_efc,nefc))
$ call errquit('grad_hnd_cos: could not retrieve nefc',917,
$ GEOM_ERR)
if (.not.bq_index_coord(cosmo_bq_efc,iefc_c))
$ call errquit('grad_hnd_cos: could not get coordinate index Bq',
$ cosmo_bq_efc,MA_ERR)
if (.not.bq_index_charge(cosmo_bq_efc,iefc_q))
$ call errquit('grad_hnd_cos: could not get charge index Bq',
$ cosmo_bq_efc,MA_ERR)
c
if (.not.ma_push_get(MT_DBL,nat,"rad",l_rad,k_rad))
$ call errquit("grad_hnd_cos: could not allocate rad",
$ ma_sizeof(MT_BYTE,nat,MT_DBL),MA_ERR)
call cosmo_def_radii(rtdb,geom,nat,dbl_mb(k_rad))
status = rtdb_get(rtdb,'cosmo:radius',mt_dbl,nat,
$ dbl_mb(k_rad))
do iat1=0,nat-1
dbl_mb(k_rad+iat1) = dbl_mb(k_rad+iat1)/bohr
enddo
c
if (.not.ma_push_get(MT_INT,nefc,"efciat",l_efciat,k_efciat))
$ call errquit("grad_hnd_cos: could not allocate efciat",
$ ma_sizeof(MT_BYTE,nefc,MT_INT),MA_ERR)
if(.not.rtdb_get(rtdb,'cosmo:efciat',mt_int,nefc,
$ int_mb(k_efciat)))
$ call errquit('grad_hnd_cos: rtdb get failed for iatefc',915,
$ rtdb_err)
c
call hf_print_set(1)
ijatom = -1
next = nxtask(nproc,task_size)
do 90, iat1 = 1, nat
do 80, iat2 = 1, iat1
ijatom = ijatom + 1
if ( ijatom .eq. next ) then
status = bas_ce2bfr(basis,iat1,iab1f,iab1l)
status = bas_ce2bfr(basis,iat2,iab2f,iab2l)
if (iab1f.le.0 .or. iab2f.le.0) then
c
c At least one center has no functions on it ... next atom
c
goto 1010
endif
if (oskel) then
if (.not. sym_atom_pair(geom, iat1, iat2, qfac))
$ goto 1010
else
qfac = 1.0d0
endif
qfac = -qfac
status = bas_ce2cnr(basis,iat1,iac1f,iac1l)
status = bas_ce2cnr(basis,iat2,iac2f,iac2l)
call ga_get (g_dens, iab1f,iab1l,iab2f,iab2l,dens,max_at_bf)
do 70, ish1 = iac1f, iac1l
if ( iat1.eq.iat2 ) iac2l = ish1
do 60, ish2 = iac2f, iac2l
C shell block in atomic (D/Dw)-matrix block
status = bas_cn2bfr(basis,ish1,if1,il1)
if1 = if1 - iab1f + 1
il1 = il1 - iab1f + 1
c
c Work out the number of Cartesian basis functions
c The integrals are evaluated in the Cartesian basis set
c and then transformed to spherical harmonics. So the
c buffer size depends on the number of Cartesian functions
c
status = bas_continfo(basis,ish1,ityp1,nprim,ngen,
+ sphcart)
if (sphcart.eq.1.and.ityp1.ge.2) then
im1 = if1 + (ityp1+1)*(ityp1+2)/2 - 1
else
im1 = il1
endif
status = bas_cn2bfr(basis,ish2,if2,il2)
if2 = if2 - iab2f + 1
il2 = il2 - iab2f + 1
c
c Same Cartesian vs spherical harmonic catastrophy as
c for ish1.
c
status = bas_continfo(basis,ish2,ityp2,nprim,ngen,
+ sphcart)
if (sphcart.eq.1.and.ityp2.ge.2) then
im2 = if2 + (ityp2+1)*(ityp2+2)/2 - 1
else
im2 = il2
endif
nint = ( im1 - if1 + 1 ) * ( im2 - if2 + 1 )
do iefc = 1, nefc
ic=1
do iat3 = 1, 3 ! centers A, B, and C
do icart = 1, 3
do ip1 = if1, im1
do ip2 = if2, im2
H(ic)=0.0D0
ic = ic + 1
enddo
enddo
enddo
enddo
C 1el. -cosmo- derivatives
c Currently calculated on for every COSMO charge
c separately.
call intd_1epot_cosmo(basis,ish1,basis,ish2,lscr,scr,
& lbuf,H,dbl_mb(iefc_c+3*(iefc-1)),
& dbl_mb(iefc_q+iefc-1),1)
C D x H
c
c Do center A (associated with ish1)
c
ic=1
do icart = 1, 3
dE = 0.D0
do ip1 = if1, il1
do ip2 = if2, il2
dE = dE + dens(ip1,ip2) * H(ic)
ic = ic + 1
enddo
enddo
if ( iat1.ne.iat2 .or. ish1.ne.ish2 ) dE = dE + dE
dE = dE * qfac
frc_cos_elq(icart,iat1)
& = frc_cos_elq(icart,iat1) - dE
enddo
c
c Do center B (associated with ish2)
c
do icart = 1, 3
dE = 0.D0
do ip1 = if1, il1
do ip2 = if2, il2
dE = dE + dens(ip1,ip2) * H(ic)
ic = ic + 1
enddo
enddo
if ( iat1.ne.iat2 .or. ish1.ne.ish2 ) then
dE = dE + dE
else
dE = 0.0d0
endif
dE = dE * qfac
frc_cos_elq(icart,iat2)
& = frc_cos_elq(icart,iat2) - dE
enddo
c
c Do center C, i.e. the Cosmo charge (associated with
c the atom stored in int_mb(k_efciat))
c
do icart = 1, 3
dE = 0.D0
do ip1 = if1, il1
do ip2 = if2, il2
dE = dE + dens(ip1,ip2) * H(ic)
ic = ic + 1
enddo
enddo
if ( iat1.ne.iat2 .or. ish1.ne.ish2 ) dE = dE + dE
dE = dE * qfac
frc_cos_elq(icart,int_mb(k_efciat+iefc-1))
& = frc_cos_elq(icart,int_mb(k_efciat+iefc-1)) - dE
enddo
enddo
60 continue
70 continue
1010 continue
next = nxtask(nproc,task_size)
endif
80 continue
90 continue
next = nxtask(-nproc,task_size)
c
if (ga_nodeid().eq.0) then
c
c Do the Nuclear - Cosmo charge part
c - 1. The derivative of matrix B (i.e. the Coulomb interaction
c between the nuclear charge and the surface charge).
c - 2. The derivative due to the change in the switching
c function (see [2] Eq.(74)). This only applies for the
c York-Karplus model.
c
invscreen = 1.0d0/(1.0d0*screen)
do ich1 = 1, nefc
if (do_cosmo_model.eq.DO_COSMO_YK) then
zeta1 = zeta*sqrt(ptspatm)
$ / (dbl_mb(k_rad+int_mb(k_efciat+ich1-1)-1)
$ * sqrt(2.0d0*pi))
xyzff = 1.0d0
do iat1 = 1, nat
if (iat1.ne.int_mb(k_efciat+ich1-1)) then
dx = coords(1,iat1,geom) - dbl_mb(0+3*(ich1-1)+iefc_c)
dy = coords(2,iat1,geom) - dbl_mb(1+3*(ich1-1)+iefc_c)
dz = coords(3,iat1,geom) - dbl_mb(2+3*(ich1-1)+iefc_c)
rr = sqrt(dx*dx+dy*dy+dz*dz)
if (rr.lt.rout(iat1)) then
xyzff = xyzff
$ * cosff((rr-rin(iat1))/(rout(iat1)-rin(iat1)))
endif
endif
enddo
endif
do iat1 = 1, nat
dx = coords(1,iat1,geom) - dbl_mb(0+3*(ich1-1)+iefc_c)
dy = coords(2,iat1,geom) - dbl_mb(1+3*(ich1-1)+iefc_c)
dz = coords(3,iat1,geom) - dbl_mb(2+3*(ich1-1)+iefc_c)
rr = sqrt(dx*dx+dy*dy+dz*dz)
c
c - term 1.
c
fact = -charge(iat1,geom)*dbl_mb(iefc_q+ich1-1) /
$ rr**3
c
c - term 2.
c
if (do_cosmo_model.eq.DO_COSMO_YK) then
if (iat1.ne.int_mb(k_efciat+ich1-1)) then
fact = fact - 2.0d0*zeta1*sqrt(2.0d0/pi)*invscreen
$ * dbl_mb(iefc_q+ich1-1)**2
$ * cosdff((rr-rin(iat1))/(rout(iat1)-rin(iat1)))
$ / (rr*xyzff*(rout(iat1)-rin(iat1))
$ *cosff((rr-rin(iat1))/(rout(iat1)-rin(iat1))))
endif
endif
c
dE = dx * fact
frc_cos_nucq(1,iat1) = frc_cos_nucq(1,iat1) + dE
frc_cos_nucq(1,int_mb(k_efciat+ich1-1))
$ = frc_cos_nucq(1,int_mb(k_efciat+ich1-1)) - dE
dE = dy * fact
frc_cos_nucq(2,iat1) = frc_cos_nucq(2,iat1) + dE
frc_cos_nucq(2,int_mb(k_efciat+ich1-1))
$ = frc_cos_nucq(2,int_mb(k_efciat+ich1-1)) - dE
dE = dz * fact
frc_cos_nucq(3,iat1) = frc_cos_nucq(3,iat1) + dE
frc_cos_nucq(3,int_mb(k_efciat+ich1-1))
$ = frc_cos_nucq(3,int_mb(k_efciat+ich1-1)) - dE
enddo
enddo
c
c Do cosmo charge - cosmo charge interaction
c
invscreen = 1.0d0/(1.0d0*screen)
do ich1 = 1, nefc
if (do_cosmo_model.eq.DO_COSMO_YK) then
zeta1 = zeta*sqrt(ptspatm)
$ / (dbl_mb(k_rad+int_mb(k_efciat+ich1-1)-1)
$ * sqrt(2.0d0*pi))
endif
do ich2 = 1, ich1-1
if (do_cosmo_model.eq.DO_COSMO_YK) then
zeta2 = zeta*sqrt(ptspatm)
$ / (dbl_mb(k_rad+int_mb(k_efciat+ich2-1)-1)
$ * sqrt(2.0d0*pi))
zeta12 = zeta1*zeta2/sqrt(zeta1**2+zeta2**2)
endif
if (ich1.ne.ich2) then
dx = dbl_mb(0+3*(ich1-1)+iefc_c)
$ - dbl_mb(0+3*(ich2-1)+iefc_c)
dy = dbl_mb(1+3*(ich1-1)+iefc_c)
$ - dbl_mb(1+3*(ich2-1)+iefc_c)
dz = dbl_mb(2+3*(ich1-1)+iefc_c)
$ - dbl_mb(2+3*(ich2-1)+iefc_c)
rr = sqrt(dx*dx+dy*dy+dz*dz)
if (rr.lt.1.0d-6) then
fact = 0.0d0
else
if (do_cosmo_model.eq.DO_COSMO_KS) then
fact = -invscreen*dbl_mb(iefc_q+ich1-1)
$ * dbl_mb(iefc_q+ich2-1)/(rr**3)
else if (do_cosmo_model.eq.DO_COSMO_YK) then
fact = +invscreen*dbl_mb(iefc_q+ich1-1)
$ * dbl_mb(iefc_q+ich2-1)
$ * (2.0d0*zeta12/sqrt(pi)/(rr**2)
$ * exp(-(zeta12*rr)**2)
$ - util_erf(zeta12*rr)/(rr**3))
else
call errquit("grad_hnd_cos: panic",
$ do_cosmo_model,UERR)
endif
endif
dE = dx * fact
frc_cos_qq(1,int_mb(k_efciat+ich1-1))
$ = frc_cos_qq(1,int_mb(k_efciat+ich1-1)) + dE
frc_cos_qq(1,int_mb(k_efciat+ich2-1))
$ = frc_cos_qq(1,int_mb(k_efciat+ich2-1)) - dE
dE = dy * fact
frc_cos_qq(2,int_mb(k_efciat+ich1-1))
$ = frc_cos_qq(2,int_mb(k_efciat+ich1-1)) + dE
frc_cos_qq(2,int_mb(k_efciat+ich2-1))
$ = frc_cos_qq(2,int_mb(k_efciat+ich2-1)) - dE
dE = dz * fact
frc_cos_qq(3,int_mb(k_efciat+ich1-1))
$ = frc_cos_qq(3,int_mb(k_efciat+ich1-1)) + dE
frc_cos_qq(3,int_mb(k_efciat+ich2-1))
$ = frc_cos_qq(3,int_mb(k_efciat+ich2-1)) - dE
endif
enddo
enddo
endif
c
if (.not.ma_pop_stack(l_efciat))
$ call errquit("grad_hnd_cos: could not deallocate l_efciat",
$ 0,MA_ERR)
if (.not.ma_pop_stack(l_rad))
$ call errquit("grad_hnd_cos: could not deallocate l_rad",
$ 0,MA_ERR)
if (.not.bq_destroy(cosmo_bq_efc))
$ call errquit("grad_hnd_cos: bq_destroy on cosmo failed",
$ 0,GEOM_ERR)
return
end