diff --git a/.gitignore b/.gitignore index 521708bcc..e06c678b6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,10 @@ *.out *.app +# Editor specific metadata +.vscode +*f90.swp + # directories /build*/ /_*/ @@ -41,7 +45,7 @@ man/*.pdf man/*.xml man/*.html -# files produces by the program +# files produced by the program xtbrestart .EDISP energy @@ -65,3 +69,6 @@ __pycache__/ python/dist python/build *.egg-info + +# external directory +ext/ diff --git a/src/gfnff/calculator.f90 b/src/gfnff/calculator.f90 index e9db22fbd..427533bb9 100644 --- a/src/gfnff/calculator.f90 +++ b/src/gfnff/calculator.f90 @@ -43,7 +43,7 @@ module xtb_gfnff_calculator public :: TGFFCalculator, newGFFCalculator - !> Calculator interface for xTB based methods + !> calculator interface for xTB based methods type, extends(TCalculator) :: TGFFCalculator type(TGFFData) :: param @@ -70,6 +70,7 @@ module xtb_gfnff_calculator subroutine newGFFCalculator(env, mol, calc, fname, restart, version) + use xtb_gfnff_param use xtb_gfnff_setup, only : gfnff_setup use xtb_disp_dftd4, only : newD3Model @@ -100,19 +101,22 @@ subroutine newGFFCalculator(env, mol, calc, fname, restart, version) call calc%topo%zero calc%update = .true. - ! global accuracy factor similar to acc in xtb used in SCF + + ! global accuracy factor similar to acc in xtb used in SCF ! calc%accuracy = 0.1_wp if (mol%n > 10000) then calc%accuracy = 2.0_wp end if - !> Obtain the parameter file + ! obtain the parameter file ! call open_file(ich, fname, 'r') exist = ich /= -1 if (exist) then call gfnff_read_param(ich, calc%param) - call close_file(ich) - else ! no parameter file, try to load internal version + call close_file(ich) + + ! no parameter file, try to load internal version ! + else call gfnff_load_param(calc%version, calc%param, exist) if (.not.exist) then call env%error('Parameter file '//fname//' not found!', source) @@ -134,7 +138,7 @@ subroutine newGFFCalculator(env, mol, calc, fname, restart, version) end subroutine newGFFCalculator - +!> GFN-FF wrapper for the single point energy evaluation subroutine singlepoint(self, env, mol, chk, printlevel, restart, & & energy, gradient, sigma, hlgap, results) @@ -182,6 +186,13 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & logical, parameter :: ccm = .true. logical :: exitRun logical :: pr + + !> GFN-FF geometry optimization + logical :: optpr + + !-------! + ! setup ! + !-------! call mol%update @@ -196,12 +207,24 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & call newBornModel(self%solvation, env, solvation, mol%at) end if - ! ------------------------------------------------------------------------ - ! actual calculation + ! to distinguish optimization, final sp and sp ! + if ((set%runtyp.eq.p_run_opt).or.(set%runtyp.eq.p_run_ohess).or. & + & (set%runtyp.eq.p_run_omd).or.(set%runtyp.eq.p_run_screen).or. & + & (set%runtyp.eq.p_run_metaopt)) then + optpr = printlevel < 2 + else + optpr = .false. + endif + pr = gff_print .and. printlevel > 0 + + !--------------------! + ! actual calculation ! + !--------------------! + call gfnff_eg(env,pr,mol%n,nint(mol%chrg),mol%at,mol%xyz,make_chrg, & & gradient,energy,results,self%param,self%topo,chk%nlist,solvation,& - & self%update,self%version,self%accuracy) + & self%update,self%version,self%accuracy,minpr=optpr) call env%check(exitRun) if (exitRun) then @@ -209,19 +232,18 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & return end if - ! ------------------------------------------------------------------------ - ! post processing of gradient and energy - - ! ------------------------------------------------------------------------ - ! various external potentials + ! ---------------------------------------! + ! post processing of gradient and energy ! + !----------------------------------------! + + ! various external potentials ! call constrain_pot(potset,mol%n,mol%at,mol%xyz,gradient,efix) call constrpot (mol%n,mol%at,mol%xyz,gradient,efix) call cavity_egrad(mol%n,mol%at,mol%xyz,efix,gradient) call metadynamic (metaset,mol%n,mol%at,mol%xyz,efix,gradient) call metadynamic (rmsdset,mol%n,mol%at,mol%xyz,efix,gradient) - ! ------------------------------------------------------------------------ - ! fixing of certain atoms + ! fixing of certain atoms ! ! print*,abs(efix/etot) energy = energy + efix results%e_total = energy @@ -233,8 +255,8 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & enddo endif - if (printlevel.ge.2) then - ! start with summary header + if (printlevel.ge.2) then + ! start with summary header ! if (.not.set%silent) then write(env%unit,'(9x,53(":"))') write(env%unit,'(9x,"::",21x,a,21x,"::")') "SUMMARY" @@ -265,15 +287,24 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, & call print_charges(ich,mol%n,chk%nlist%q) call close_file(ich) end if - endif + + else if (set%mode_extrun .eq. p_ext_oniom) then + write(env%unit,outfmt) "total energy ", results%e_total,"Eh " + write(env%unit,outfmt) "gradient norm ", results%gnorm, "Eh/a0" + + endif end subroutine singlepoint subroutine print_gfnff_results(iunit,res_gff,verbose,lsolv) + use xtb_type_data - integer, intent(in) :: iunit ! file handle (usually output_unit=6) + + !> file handle (usually output_unit=6) + integer, intent(in) :: iunit type(scc_results), intent(in) :: res_gff logical,intent(in) :: verbose,lsolv + write(iunit,outfmt) "bond energy ", res_gff%e_bond, "Eh " write(iunit,outfmt) "angle energy ", res_gff%e_angl, "Eh " write(iunit,outfmt) "torsion energy ", res_gff%e_tors, "Eh " diff --git a/src/gfnff/gfnff_eg.f90 b/src/gfnff/gfnff_eg.f90 index 91c51afdb..ae8087e67 100644 --- a/src/gfnff/gfnff_eg.f90 +++ b/src/gfnff/gfnff_eg.f90 @@ -16,6 +16,7 @@ ! along with xtb. If not, see . module xtb_gfnff_eg + use xtb_gfnff_ini2 use xtb_gfnff_data, only : TGFFData use xtb_gfnff_neighbourlist, only : TGFFNeighbourList, new @@ -59,142 +60,158 @@ module xtb_gfnff_eg ! !--------------------------------------------------- - subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & - & param,topo,nlist,solvation,update,version,accuracy) - use xtb_mctc_accuracy, only : wp - use xtb_gfnff_param, only : efield, gffVersion, gfnff_thresholds - use xtb_type_data - use xtb_type_timer - use xtb_gfnff_gdisp0 - use xtb_mctc_constants - implicit none - character(len=*), parameter :: source = 'gfnff_eg' - type(TEnvironment), intent(inout) :: env - type(scc_results),intent(out) :: res_gff - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - type(TGFFNeighbourList), intent(inout) :: nlist - type(TBorn), allocatable, intent(inout) :: solvation - logical, intent(in) :: update - integer, intent(in) :: version - real(wp), intent(in) :: accuracy - integer n - integer ichrg - integer at(n) - real*8 xyz(3,n) - real*8 g (3,n) - real*8 etot - logical pr - logical makeq - - real*8 edisp,ees,ebond,eangl,etors,erep,ehb,exb,ebatm,eext - real*8 :: gsolv, gborn, ghb, gsasa, gshift - - integer i,j,k,l,m,ij,nd3 - integer ati,atj,iat,jat - integer hbA,hbB,nbk,nbnbk - integer lin - logical ex, require_update - integer nhb1, nhb2, nxb - real*8 r2,rab,qq0,erff,dd,dum1,r3(3),t8,dum,t22,t39 - real*8 dx,dy,dz,yy,t4,t5,t6,alpha,t20 - real*8 repab,t16,t19,t26,t27,xa,ya,za,cosa,de,t28 - real*8 gammij,eesinf,etmp,phi,valijklff - real*8 omega,rn,dr,g3tmp(3,3),g4tmp(3,4) - real*8 rij,drij(3,n) - - real*8, allocatable :: grab0(:,:,:), rab0(:), eeqtmp(:,:) - real*8, allocatable :: cn(:), dcn(:,:,:), qtmp(:) - real*8, allocatable :: hb_cn(:), hb_dcn(:,:,:) - real*8, allocatable :: sqrab(:), srab(:) - real*8, allocatable :: g5tmp(:,:) - integer,allocatable :: d3list(:,:) - type(tb_timer) :: timer - real(wp) :: dispthr, cnthr, repthr, hbthr1, hbthr2 - - call gfnff_thresholds(accuracy, dispthr, cnthr, repthr, hbthr1, hbthr2) - - g = 0 - exb = 0 - ehb = 0 - erep= 0 - ees = 0 - edisp=0 - ebond=0 - eangl=0 - etors=0 - ebatm=0 - eext =0 +subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & + & param,topo,nlist,solvation,update,version,accuracy,minpr) - gsolv = 0.0d0 - gsasa = 0.0d0 - gborn = 0.0d0 - ghb = 0.0d0 - gshift = 0.0d0 - - allocate(sqrab(n*(n+1)/2),srab(n*(n+1)/2),qtmp(n),g5tmp(3,n), & - & eeqtmp(2,n*(n+1)/2),d3list(2,n*(n+1)/2),dcn(3,n,n),cn(n), & - & hb_dcn(3,n,n),hb_cn(n)) + use xtb_mctc_accuracy, only : wp + use xtb_gfnff_param, only : efield, gffVersion, gfnff_thresholds + use xtb_type_data + use xtb_type_timer + use xtb_gfnff_gdisp0 + use xtb_mctc_constants + implicit none - if (pr) call timer%new(10 + count([allocated(solvation)]),.false.) + character(len=*), parameter :: source = 'gfnff_eg' + type(TEnvironment), intent(inout) :: env + type(scc_results),intent(out) :: res_gff + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + type(TGFFNeighbourList), intent(inout) :: nlist + type(TBorn), allocatable, intent(inout) :: solvation + logical, intent(in) :: update + integer, intent(in) :: version + real(wp), intent(in) :: accuracy + logical, intent(in), optional :: minpr + + integer n + integer ichrg + integer at(n) + real*8 xyz(3,n) + real*8 g (3,n) + real*8 etot + logical pr + logical makeq + + real*8 edisp,ees,ebond,eangl,etors,erep,ehb,exb,ebatm,eext + real*8 :: gsolv, gborn, ghb, gsasa, gshift + + integer i,j,k,l,m,ij,nd3 + integer ati,atj,iat,jat + integer hbA,hbB,nbk,nbnbk + integer lin + logical ex, require_update + integer nhb1, nhb2, nxb + real*8 r2,rab,qq0,erff,dd,dum1,r3(3),t8,dum,t22,t39 + real*8 dx,dy,dz,yy,t4,t5,t6,alpha,t20 + real*8 repab,t16,t19,t26,t27,xa,ya,za,cosa,de,t28 + real*8 gammij,eesinf,etmp,phi,valijklff + real*8 omega,rn,dr,g3tmp(3,3),g4tmp(3,4) + real*8 rij,drij(3,n) + + real*8, allocatable :: grab0(:,:,:), rab0(:), eeqtmp(:,:) + real*8, allocatable :: cn(:), dcn(:,:,:), qtmp(:) + real*8, allocatable :: hb_cn(:), hb_dcn(:,:,:) + real*8, allocatable :: sqrab(:), srab(:) + real*8, allocatable :: g5tmp(:,:) + integer,allocatable :: d3list(:,:) + type(tb_timer) :: timer + real(wp) :: dispthr, cnthr, repthr, hbthr1, hbthr2 + + call gfnff_thresholds(accuracy, dispthr, cnthr, repthr, hbthr1, hbthr2) + + g = 0 + exb = 0 + ehb = 0 + erep= 0 + ees = 0 + edisp=0 + ebond=0 + eangl=0 + etors=0 + ebatm=0 + eext =0 + + gsolv = 0.0d0 + gsasa = 0.0d0 + gborn = 0.0d0 + ghb = 0.0d0 + gshift = 0.0d0 + + allocate(sqrab(n*(n+1)/2),srab(n*(n+1)/2),qtmp(n),g5tmp(3,n), & + & eeqtmp(2,n*(n+1)/2),d3list(2,n*(n+1)/2),dcn(3,n,n),cn(n), & + & hb_dcn(3,n,n),hb_cn(n)) + + if (pr) then + + call timer%new(10 + count([allocated(solvation)]),.false.) + + else if (present(minpr)) then + + ! to iteration time for single cycle ! + if (minpr) then + call timer%new(1, .false.) + call timer%measure(1,'iter. time') + end if + + endif - if (pr) call timer%measure(1,'distance/D3 list') - nd3=0 - do i=1,n - ij = i*(i-1)/2 - do j=1,i-1 - k = ij+j - sqrab(k)=(xyz(1,i)-xyz(1,j))**2+& - & (xyz(2,i)-xyz(2,j))**2+& - & (xyz(3,i)-xyz(3,j))**2 - if(sqrab(k).lt.dispthr)then + if (pr) call timer%measure(1,'distance/D3 list') + nd3=0 + do i=1,n + ij = i*(i-1)/2 + do j=1,i-1 + k = ij+j + sqrab(k)=(xyz(1,i)-xyz(1,j))**2+& + & (xyz(2,i)-xyz(2,j))**2+& + & (xyz(3,i)-xyz(3,j))**2 + if(sqrab(k).lt.dispthr)then nd3=nd3+1 d3list(1,nd3)=i d3list(2,nd3)=j - endif - srab (k)=sqrt(sqrab(k)) - enddo -! The loop above only runs over the off diagonal elements -! This initializes the unitialized diagonal to zero but does not -! add it to the dispersion list. - sqrab(ij + i) = 0.0d0 - srab(ij + i) = 0.0d0 + endif + srab (k)=sqrt(sqrab(k)) enddo - if (pr) call timer%measure(1) - -!!!!!!!!!!!! -! Setup HB -!!!!!!!!!!!! - if (pr) call timer%measure(10,'HB/XB (incl list setup)') - if (allocated(nlist%q)) then - nlist%initialized = size(nlist%q) == n - end if - call gfnff_hbset0(n,at,xyz,sqrab,topo,nhb1,nhb2,nxb,hbthr1,hbthr2) - nlist%initialized = nlist%initialized .and. nhb1 <= nlist%nhb1 & - & .and. nhb2 <= nlist%nhb2 .and. nxb <= nlist%nxb - require_update = .not.nlist%initialized - if (.not.nlist%initialized) then - if (pr) then - write(env%unit,'(10x,"Number of HB bonds (bound hydrogen)",5x,i0,x,i0,x,i0)') & + ! The loop above only runs over the off diagonal elements ! + ! This initializes the unitialized diagonal to zero but does not ! + ! add it to the dispersion list. ! + sqrab(ij + i) = 0.0d0 + srab(ij + i) = 0.0d0 + enddo + if (pr) call timer%measure(1) + + !----------! + ! Setup HB ! + !----------! + + if (pr) call timer%measure(10,'HB/XB (incl list setup)') + if (allocated(nlist%q)) then + nlist%initialized = size(nlist%q) == n + end if + call gfnff_hbset0(n,at,xyz,sqrab,topo,nhb1,nhb2,nxb,hbthr1,hbthr2) + nlist%initialized = nlist%initialized .and. nhb1 <= nlist%nhb1 & + & .and. nhb2 <= nlist%nhb2 .and. nxb <= nlist%nxb + require_update = .not.nlist%initialized + if (.not.nlist%initialized) then + if (pr) then + write(env%unit,'(10x,"Number of HB bonds (bound hydrogen)",5x,i0,x,i0,x,i0)') & & nhb1 - write(env%unit,'(10x,"Number of HB bonds (unbound hydrogen)",3x,i0,x,i0,x,i0)') & + write(env%unit,'(10x,"Number of HB bonds (unbound hydrogen)",3x,i0,x,i0,x,i0)') & & nhb2 - write(env%unit,'(10x,"Number of XB bonds",22x,i0,x,i0,x,i0)') & + write(env%unit,'(10x,"Number of XB bonds",22x,i0,x,i0,x,i0)') & & nxb - end if - call new(nlist, n, 5*nhb1, 5*nhb2, 3*nxb) - nlist%hbrefgeo(:, :) = xyz end if - if (update .or. require_update) then - call gfnff_hbset(n,at,xyz,sqrab,topo,nlist,hbthr1,hbthr2) - end if - if (pr) call timer%measure(10) - -!!!!!!!!!!!!! -! Setup -! GBSA -!!!!!!!!!!!!! + call new(nlist, n, 5*nhb1, 5*nhb2, 3*nxb) + nlist%hbrefgeo(:, :) = xyz + end if + if (update .or. require_update) then + call gfnff_hbset(n,at,xyz,sqrab,topo,nlist,hbthr1,hbthr2) + end if + if (pr) call timer%measure(10) + + !------------! + ! Setup GBSA ! + !------------! if (allocated(solvation)) then call timer%measure(11, "GBSA") @@ -202,23 +219,22 @@ subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & call timer%measure(11) endif - -!!!!!!!!!!!!! -! REP part -! non-bonded -!!!!!!!!!!!!! - - if (pr) call timer%measure(2,'non bonded repulsion') - !$omp parallel do default(none) reduction(+:erep, g) & - !$omp shared(n, at, xyz, srab, sqrab, repthr, topo, param) & - !$omp private(iat, jat, m, ij, ati, atj, rab, r2, r3, t8, t16, t19, t26, t27) - do iat=1,n - m=iat*(iat-1)/2 - do jat=1,iat-1 + !------------! + ! REP part ! + ! non-bonded ! + !------------! + + if (pr) call timer%measure(2,'non bonded repulsion') + !$omp parallel do default(none) reduction(+:erep, g) & + !$omp shared(n, at, xyz, srab, sqrab, repthr, topo, param) & + !$omp private(iat, jat, m, ij, ati, atj, rab, r2, r3, t8, t16, t19, t26, t27) + do iat=1,n + m=iat*(iat-1)/2 + do jat=1,iat-1 ij=m+jat r2=sqrab(ij) - if(r2.gt.repthr) cycle ! cut-off - if(topo%bpair(ij).eq.1) cycle ! list avoided because of memory + if(r2.gt.repthr) cycle ! cut-off ! + if(topo%bpair(ij).eq.1) cycle ! list avoided because of memory ! ati=at(iat) atj=at(jat) rab=srab(ij) @@ -231,17 +247,14 @@ subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & r3 =(xyz(:,iat)-xyz(:,jat))*t27 g(:,iat)=g(:,iat)-r3 g(:,jat)=g(:,jat)+r3 - enddo enddo - !$omp end parallel do - if (pr) call timer%measure(2) + enddo + !$omp end parallel do + if (pr) call timer%measure(2) -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! just a extremely crude mode for 2D-3D conversion -! i.e. an harmonic potential with estimated Re -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (version == gffVersion%harmonic2020) then + ! just a extremely crude mode for 2D-3D conversion ! + ! i.e. an harmonic potential with estimated Re ! + if (version == gffVersion%harmonic2020) then ebond=0 !$omp parallel do default(none) reduction(+:ebond, g) & !$omp shared(topo, param, xyz, at) private(i, iat, jat, rab, r2, r3, rn, dum) @@ -260,88 +273,89 @@ subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & !$omp end parallel do etot = ebond + erep return - endif + endif -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! erf CN and gradient for disp -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !------------------------------! + ! erf CN and gradient for disp ! + !------------------------------! - if (pr) call timer%measure(3,'dCN') - call gfnff_dlogcoord(n,at,xyz,srab,cn,dcn,cnthr,param) ! new erf used in GFN0 - if (sum(topo%nr_hb).gt.0) call dncoord_erf(n,at,xyz,param%rcov,hb_cn,hb_dcn,900.0d0,topo) ! HB erf CN - if (pr) call timer%measure(3) + if (pr) call timer%measure(3,'dCN') + call gfnff_dlogcoord(n,at,xyz,srab,cn,dcn,cnthr,param) ! new erf used in GFN0 + if (sum(topo%nr_hb).gt.0) call dncoord_erf(n,at,xyz,param%rcov,hb_cn,hb_dcn,900.0d0,topo) ! HB erf CN + if (pr) call timer%measure(3) -!!!!!! -! EEQ -!!!!!! + !-----! + ! EEQ ! + !-----! - if (pr) call timer%measure(4,'EEQ energy and q') - call goed_gfnff(env,accuracy.gt.1,n,at,sqrab,srab,& ! modified version - & dfloat(ichrg),eeqtmp,cn,nlist%q,ees,solvation,param,topo) ! without dq/dr - if (pr) call timer%measure(4) + if (pr) call timer%measure(4,'EEQ energy and q') + call goed_gfnff(env,accuracy.gt.1,n,at,sqrab,srab,& ! modified version + & dfloat(ichrg),eeqtmp,cn,nlist%q,ees,solvation,param,topo) ! without dq/dr + if (pr) call timer%measure(4) -!!!!!!!! -!D3(BJ) -!!!!!!!! + !--------! + ! D3(BJ) ! + !--------! - if (pr) call timer%measure(5,'D3') - if(nd3.gt.0) then - call d3_gradient(topo%dispm, n, at, xyz, nd3, d3list, topo%zetac6, & - & param%d3r0, sqrtZr4r2, 4.0d0, param%dispscale, cn, dcn, edisp, g) - endif - deallocate(d3list) - if (pr) call timer%measure(5) - -!!!!!!!! -! ES part -!!!!!!!! - if (pr) call timer%measure(6,'EEQ gradient') - !$omp parallel do default(none) reduction (+:g) & - !$omp shared(topo,nlist,n,sqrab,srab,eeqtmp,xyz,at) & - !$omp private(i,j,k,ij,r3,r2,rab,gammij,erff,dd) - do i=1,n - k = i*(i-1)/2 - do j=1,i-1 - ij = k+j - r2 =sqrab(ij) - rab= srab(ij) - gammij=eeqtmp(1,ij) - erff =eeqtmp(2,ij) - dd=(2.0d0*gammij*exp(-gammij**2*r2) & - & /(sqrtpi*r2)-erff/(rab*r2))*nlist%q(i)*nlist%q(j) - r3=(xyz(:,i)-xyz(:,j))*dd - g(:,i)=g(:,i)+r3 - g(:,j)=g(:,j)-r3 - enddo + if (pr) call timer%measure(5,'D3') + if(nd3.gt.0) then + call d3_gradient(topo%dispm, n, at, xyz, nd3, d3list, topo%zetac6, & + & param%d3r0, sqrtZr4r2, 4.0d0, param%dispscale, cn, dcn, edisp, g) + endif + deallocate(d3list) + if (pr) call timer%measure(5) + + !---------! + ! ES part ! + !---------! + + if (pr) call timer%measure(6,'EEQ gradient') + !$omp parallel do default(none) reduction (+:g) & + !$omp shared(topo,nlist,n,sqrab,srab,eeqtmp,xyz,at) & + !$omp private(i,j,k,ij,r3,r2,rab,gammij,erff,dd) + do i=1,n + k = i*(i-1)/2 + do j=1,i-1 + ij = k+j + r2 =sqrab(ij) + rab= srab(ij) + gammij=eeqtmp(1,ij) + erff =eeqtmp(2,ij) + dd=(2.0d0*gammij*exp(-gammij**2*r2) & + & /(sqrtpi*r2)-erff/(rab*r2))*nlist%q(i)*nlist%q(j) + r3=(xyz(:,i)-xyz(:,j))*dd + g(:,i)=g(:,i)+r3 + g(:,j)=g(:,j)-r3 enddo - !$omp end parallel do - if(.not.pr) deallocate(eeqtmp) - - if (allocated(solvation)) then - call timer%measure(11, "GBSA") - call solvation%addGradient(env, at, xyz, nlist%q, nlist%q, g) - call solvation%getEnergyParts(env, nlist%q, nlist%q, gborn, ghb, gsasa, & - & gshift) - gsolv = gsasa + gborn + ghb + gshift - call timer%measure(11) - else - gborn = 0.0d0 - ghb = 0.0d0 - endif + enddo + !$omp end parallel do + if(.not.pr) deallocate(eeqtmp) - do i=1,n - qtmp(i)=nlist%q(i)*param%cnf(at(i))/(2.0d0*sqrt(cn(i))+1.d-16) - enddo + if (allocated(solvation)) then + call timer%measure(11, "GBSA") + call solvation%addGradient(env, at, xyz, nlist%q, nlist%q, g) + call solvation%getEnergyParts(env, nlist%q, nlist%q, gborn, ghb, gsasa, & + & gshift) + gsolv = gsasa + gborn + ghb + gshift + call timer%measure(11) + else + gborn = 0.0d0 + ghb = 0.0d0 + endif - call mctc_gemv(dcn, qtmp, g, alpha=-1.0_wp, beta=1.0_wp) - if (pr) call timer%measure(6) + do i=1,n + qtmp(i)=nlist%q(i)*param%cnf(at(i))/(2.0d0*sqrt(cn(i))+1.d-16) + enddo -!!!!!!!!!!!!!!!!!! -! SRB bonded part -!!!!!!!!!!!!!!!!!! + call mctc_gemv(dcn, qtmp, g, alpha=-1.0_wp, beta=1.0_wp) + if (pr) call timer%measure(6) - if (pr) call timer%measure(7,'bonds') - if(topo%nbond.gt.0)then + !-----------------! + ! SRB bonded part ! + !-----------------! + + if (pr) call timer%measure(7,'bonds') + if(topo%nbond.gt.0)then allocate(grab0(3,n,topo%nbond),rab0(topo%nbond)) rab0(:)=topo%vbond(1,:) ! shifts call gfnffdrab(n,at,xyz,cn,dcn,topo%nbond,topo%blist,rab0,grab0) @@ -361,19 +375,17 @@ subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & rij=rab0(i) drij=grab0(:,:,i) if (topo%nr_hb(i).ge.1) then - call egbond_hb(i,iat,jat,rab,rij,drij,hb_cn,hb_dcn,n,at,xyz,ebond,g,param,topo) + call egbond_hb(i,iat,jat,rab,rij,drij,hb_cn,hb_dcn,n,at,xyz,ebond,g,param,topo) else - call egbond(i,iat,jat,rab,rij,drij,n,at,xyz,ebond,g,topo) + call egbond(i,iat,jat,rab,rij,drij,n,at,xyz,ebond,g,topo) end if enddo !$omp end parallel do deallocate(hb_dcn) -!!!!!!!!!!!!!!!!!! -! bonded REP -!!!!!!!!!!!!!!!!!! - + ! bonded REP ! + !$omp parallel do default(none) reduction(+:erep, g) & !$omp shared(topo, param, at, sqrab, srab, xyz) & !$omp private(i, iat, jat, ij, xa, ya, za, dx, dy, dz, r2, rab, ati, atj, & @@ -407,851 +419,915 @@ subroutine gfnff_eg(env,pr,n,ichrg,at,xyz,makeq,g,etot,res_gff, & g(3,jat)=g(3,jat)+dz*t27 enddo !$omp end parallel do - endif - if (pr) call timer%measure(7) - -!!!!!!!!!!!!!!!!!! -! bend -!!!!!!!!!!!!!!!!!! - - if (pr) call timer%measure(8,'bend and torsion') - if(topo%nangl.gt.0)then - !$omp parallel do default(none) reduction (+:eangl, g) & - !$omp shared(n, at, xyz, topo, param) & - !$omp private(m, j, i, k, etmp, g3tmp) - do m=1,topo%nangl - j = topo%alist(1,m) - i = topo%alist(2,m) - k = topo%alist(3,m) - call egbend(m,j,i,k,n,at,xyz,etmp,g3tmp,param,topo) - g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) - g(1:3,i)=g(1:3,i)+g3tmp(1:3,2) - g(1:3,k)=g(1:3,k)+g3tmp(1:3,3) - eangl=eangl+etmp - enddo - !$omp end parallel do - endif + endif + if (pr) call timer%measure(7) + + !------! + ! bend ! + !------! + + if (pr) call timer%measure(8,'bend and torsion') + if(topo%nangl.gt.0)then + !$omp parallel do default(none) reduction (+:eangl, g) & + !$omp shared(n, at, xyz, topo, param) & + !$omp private(m, j, i, k, etmp, g3tmp) + do m=1,topo%nangl + j = topo%alist(1,m) + i = topo%alist(2,m) + k = topo%alist(3,m) + call egbend(m,j,i,k,n,at,xyz,etmp,g3tmp,param,topo) + g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) + g(1:3,i)=g(1:3,i)+g3tmp(1:3,2) + g(1:3,k)=g(1:3,k)+g3tmp(1:3,3) + eangl=eangl+etmp + enddo + !$omp end parallel do + endif -!!!!!!!!!!!!!!!!!! -! torsion -!!!!!!!!!!!!!!!!!! - - if(topo%ntors.gt.0)then - !$omp parallel do default(none) reduction(+:etors, g) & - !$omp shared(param, topo, n, at, xyz) & - !$omp private(m, i, j, k, l, etmp, g4tmp) - do m=1,topo%ntors - i=topo%tlist(1,m) - j=topo%tlist(2,m) - k=topo%tlist(3,m) - l=topo%tlist(4,m) - call egtors(m,i,j,k,l,n,at,xyz,etmp,g4tmp,param,topo) - g(1:3,i)=g(1:3,i)+g4tmp(1:3,1) - g(1:3,j)=g(1:3,j)+g4tmp(1:3,2) - g(1:3,k)=g(1:3,k)+g4tmp(1:3,3) - g(1:3,l)=g(1:3,l)+g4tmp(1:3,4) - etors=etors+etmp - enddo - !$omp end parallel do - endif - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! triple bonded carbon torsion potential -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (allocated(topo%sTorsl)) then - m = size(topo%sTorsl(1,:)) - if (m.ne.0) then - do i=1, m - call sTors_eg(m, n, xyz, topo, etmp, g5tmp) - etors = etors + etmp - g = g + g5tmp - enddo - endif - endif - if (pr) call timer%measure(8) - -!!!!!!!!!!!!!!!!!! -! BONDED ATM -!!!!!!!!!!!!!!!!!! - - if (pr) call timer%measure(9,'bonded ATM') - if(topo%nbatm.gt.0) then - !$omp parallel do default(none) reduction(+:ebatm, g) & - !$omp shared(n, at, xyz, srab, sqrab, topo, param) & - !$omp private(i, j, k, l, etmp, g3tmp) - do i=1,topo%nbatm - j=topo%b3list(1,i) - k=topo%b3list(2,i) - l=topo%b3list(3,i) - call batmgfnff_eg(n,j,k,l,at,xyz,topo%qa,sqrab,srab,etmp,g3tmp,param) - g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) - g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) - g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) - ebatm=ebatm+etmp - enddo - !$omp end parallel do - endif - if (pr) call timer%measure(9) - -!!!!!!!!!!!!!!!!!! -! EHB -!!!!!!!!!!!!!!!!!! - - if (pr) call timer%measure(10,'HB/XB (incl list setup)') - - if(nlist%nhb1.gt.0) then - !$omp parallel do default(none) reduction(+:ehb, g) & - !$omp shared(topo, nlist, param, n, at, xyz, sqrab, srab) & - !$omp private(i, j, k, l, etmp, g3tmp) - do i=1,nlist%nhb1 - j=nlist%hblist1(1,i) - k=nlist%hblist1(2,i) - l=nlist%hblist1(3,i) - call abhgfnff_eg1(n,j,k,l,at,xyz,topo%qa,sqrab,srab,etmp,g3tmp,param,topo) - g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) - g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) - g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) - ehb=ehb+etmp - nlist%hbe1(i)=etmp ! HB energies + !---------! + ! torsion ! + !---------! + + if(topo%ntors.gt.0)then + !$omp parallel do default(none) reduction(+:etors, g) & + !$omp shared(param, topo, n, at, xyz) & + !$omp private(m, i, j, k, l, etmp, g4tmp) + do m=1,topo%ntors + i=topo%tlist(1,m) + j=topo%tlist(2,m) + k=topo%tlist(3,m) + l=topo%tlist(4,m) + call egtors(m,i,j,k,l,n,at,xyz,etmp,g4tmp,param,topo) + g(1:3,i)=g(1:3,i)+g4tmp(1:3,1) + g(1:3,j)=g(1:3,j)+g4tmp(1:3,2) + g(1:3,k)=g(1:3,k)+g4tmp(1:3,3) + g(1:3,l)=g(1:3,l)+g4tmp(1:3,4) + etors=etors+etmp + enddo + !$omp end parallel do + endif + + !----------------------------------------! + ! triple bonded carbon torsion potential ! + !----------------------------------------! + + if (allocated(topo%sTorsl)) then + m = size(topo%sTorsl(1,:)) + if (m.ne.0) then + do i=1, m + call sTors_eg(m, n, xyz, topo, etmp, g5tmp) + etors = etors + etmp + g = g + g5tmp enddo - !$omp end parallel do endif + endif + if (pr) call timer%measure(8) + + !------------! + ! BONDED ATM ! + !------------! + + if (pr) call timer%measure(9,'bonded ATM') + if(topo%nbatm.gt.0) then + !$omp parallel do default(none) reduction(+:ebatm, g) & + !$omp shared(n, at, xyz, srab, sqrab, topo, param) & + !$omp private(i, j, k, l, etmp, g3tmp) + do i=1,topo%nbatm + j=topo%b3list(1,i) + k=topo%b3list(2,i) + l=topo%b3list(3,i) + call batmgfnff_eg(n,j,k,l,at,xyz,topo%qa,sqrab,srab,etmp,g3tmp,param) + g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) + g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) + g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) + ebatm=ebatm+etmp + enddo + !$omp end parallel do + endif + if (pr) call timer%measure(9) + + !-----! + ! EHB ! + !-----! + + if (pr) call timer%measure(10,'HB/XB (incl list setup)') + + if(nlist%nhb1.gt.0) then + !$omp parallel do default(none) reduction(+:ehb, g) & + !$omp shared(topo, nlist, param, n, at, xyz, sqrab, srab) & + !$omp private(i, j, k, l, etmp, g3tmp) + do i=1,nlist%nhb1 + j=nlist%hblist1(1,i) + k=nlist%hblist1(2,i) + l=nlist%hblist1(3,i) + call abhgfnff_eg1(n,j,k,l,at,xyz,topo%qa,sqrab,srab,etmp,g3tmp,param,topo) + g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) + g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) + g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) + ehb=ehb+etmp + nlist%hbe1(i)=etmp ! HB energies ! + enddo + !$omp end parallel do + endif - if(nlist%nhb2.gt.0) then - !$omp parallel do default(none) reduction(+:ehb, g) & - !$omp shared(topo, nlist, param, n, at, xyz, sqrab, srab) & - !$omp private(i, j, k, l, nbk, nbnbk, etmp, g5tmp) - do i=1,nlist%nhb2 - j=nlist%hblist2(1,i) - k=nlist%hblist2(2,i) - l=nlist%hblist2(3,i) - ! prepare variables for check in carbonyl/nitro case - ! Number neighbors of C/N should be > 1 for carbonyl/nitro - nbk=topo%nb(1,k) ! index of first neighbor of k - ! get number neighbors of neighbor of k - nbnbk=0 - if(nbk.ne.0) nbnbk=topo%nb(20,nbk) - !Carbonyl case R-C=O...H_A - if(at(k).eq.8.and.topo%nb(20,k).eq.1.and.at(topo%nb(1,k)).eq.6 & - & .and.nbnbk.gt.1) then + if(nlist%nhb2.gt.0) then + !$omp parallel do default(none) reduction(+:ehb, g) & + !$omp shared(topo, nlist, param, n, at, xyz, sqrab, srab) & + !$omp private(i, j, k, l, nbk, nbnbk, etmp, g5tmp) + do i=1,nlist%nhb2 + + j=nlist%hblist2(1,i) + k=nlist%hblist2(2,i) + l=nlist%hblist2(3,i) + + ! prepare variables for check in carbonyl/nitro case ! + ! Number neighbors of C/N should be > 1 for carbonyl/nitro ! + nbk=topo%nb(1,k) ! index of first neighbor of k ! + + ! get number neighbors of neighbor of k ! + nbnbk=0 + if(nbk.ne.0) nbnbk=topo%nb(20,nbk) + + ! Carbonyl case R-C=O...H_A ! + if(at(k).eq.8.and.topo%nb(20,k).eq.1.and.at(topo%nb(1,k)).eq.6 & + & .and.nbnbk.gt.1) then call abhgfnff_eg3(n,j,k,l,at,xyz,topo%qa,sqrab,srab, & - & etmp,g5tmp,param,topo) - !Nitro case R-N=O...H_A - else if(at(k).eq.8.and.topo%nb(20,k).eq.1.and.at(topo%nb(1,k)).eq.7 & - & .and.nbnbk.gt.1) then + & etmp,g5tmp,param,topo) + + ! Nitro case R-N=O...H_A ! + else if(at(k).eq.8.and.topo%nb(20,k).eq.1.and.at(topo%nb(1,k)).eq.7 & + & .and.nbnbk.gt.1) then call abhgfnff_eg3(n,j,k,l,at,xyz,topo%qa,sqrab,srab, & - & etmp,g5tmp,param,topo) - !N hetero aromat - else if(at(k).eq.7.and.topo%nb(20,k).eq.2) then + & etmp,g5tmp,param,topo) + + ! N hetero aromat ! + else if(at(k).eq.7.and.topo%nb(20,k).eq.2) then call abhgfnff_eg2_rnr(n,j,k,l,at,xyz,topo%qa,sqrab,srab, & - & etmp,g5tmp,param,topo) - else - !Default + & etmp,g5tmp,param,topo) + + ! default ! + else call abhgfnff_eg2new(n,j,k,l,at,xyz,topo%qa,sqrab,srab, & - & etmp,g5tmp,param,topo) - end if - g=g+g5tmp - ehb=ehb+etmp - nlist%hbe2(i)=etmp - enddo - !$omp end parallel do - endif - -!!!!!!!!!!!!!!!!!! -! EXB -!!!!!!!!!!!!!!!!!! - - if(nlist%nxb.gt.0) then - !$omp parallel do default(none) reduction(+:exb, g) & - !$omp shared(topo, nlist, param, n, at, xyz) & - !$omp private(i, j, k, l, etmp, g3tmp) - do i=1,nlist%nxb - j=nlist%hblist3(1,i) - k=nlist%hblist3(2,i) - l=nlist%hblist3(3,i) - call rbxgfnff_eg(n,j,k,l,at,xyz,topo%qa,etmp,g3tmp,param) - g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) - g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) - g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) - exb=exb+etmp - nlist%hbe3(i)=etmp - enddo - !$omp end parallel do - endif - if (pr) call timer%measure(10) + & etmp,g5tmp,param,topo) + end if + g=g+g5tmp + ehb=ehb+etmp + nlist%hbe2(i)=etmp + enddo + !$omp end parallel do + endif + + !-----! + ! EXB ! + !-----! + + if(nlist%nxb.gt.0) then + !$omp parallel do default(none) reduction(+:exb, g) & + !$omp shared(topo, nlist, param, n, at, xyz) & + !$omp private(i, j, k, l, etmp, g3tmp) + do i=1,nlist%nxb + j=nlist%hblist3(1,i) + k=nlist%hblist3(2,i) + l=nlist%hblist3(3,i) + call rbxgfnff_eg(n,j,k,l,at,xyz,topo%qa,etmp,g3tmp,param) + g(1:3,j)=g(1:3,j)+g3tmp(1:3,1) + g(1:3,k)=g(1:3,k)+g3tmp(1:3,2) + g(1:3,l)=g(1:3,l)+g3tmp(1:3,3) + exb=exb+etmp + nlist%hbe3(i)=etmp + enddo + !$omp end parallel do + endif + if (pr) call timer%measure(10) + ! external stuff ! + if(sum(abs(efield)).gt.1d-6)then + do i=1,n + r3(:) =-nlist%q(i)*efield(:) + g(:,i)= g(:,i) + r3(:) + eext = eext + r3(1)*(xyz(1,i)-topo%xyze0(1,i))+& + & r3(2)*(xyz(2,i)-topo%xyze0(2,i))+& + & r3(3)*(xyz(3,i)-topo%xyze0(3,i)) + enddo + endif -!!!!!!!!!!!!!!!!!! -! external stuff -!!!!!!!!!!!!!!!!!! + !--------------! + ! total energy ! + !--------------! + + etot = ees + edisp + erep + ebond & + & + eangl + etors + ehb + exb + ebatm + eext & + & + gsolv + + !----------! + ! printout ! + !----------! + if (pr) then + + call timer%write(6,'E+G') + if(abs(sum(nlist%q)-ichrg).gt.1.d-1) then ! check EEQ only once + write(env%unit,*) nlist%q + write(env%unit,*) sum(nlist%q),ichrg + call env%error('EEQ charge constrain error', source) + return + endif + r3 = 0 + do i=1,n + r3(:) = r3(:)+nlist%q(i)*xyz(:,i) + enddo - if(sum(abs(efield)).gt.1d-6)then - do i=1,n - r3(:) =-nlist%q(i)*efield(:) - g(:,i)= g(:,i) + r3(:) - eext = eext + r3(1)*(xyz(1,i)-topo%xyze0(1,i))+& - & r3(2)*(xyz(2,i)-topo%xyze0(2,i))+& - & r3(3)*(xyz(3,i)-topo%xyze0(3,i)) - enddo + ! just for fit De calc ! + sqrab = 1.d+12 + srab = 1.d+6 + cn = 0 + + ! asymtotically for R=inf, Etot is the SIE contaminted EES ! + ! which is computed here to get the atomization energy De,n,at(n) ! + call goed_gfnff(env,.true.,n,at,sqrab,srab,dfloat(ichrg),eeqtmp,cn,qtmp,eesinf,solvation,param,topo) + de=-(etot - eesinf) + + ! if geometry optimization ! + else if (present(minpr)) then + + if (minpr) then + call timer%measure(1) + ! stop timer and add tag ! + call timer%write_timing(env%unit,1) endif -!!!!!!!!!!!!!!!!!! -! total energy -!!!!!!!!!!!!!!!!!! - etot = ees + edisp + erep + ebond & - & + eangl + etors + ehb + exb + ebatm + eext & - & + gsolv + endif -!!!!!!!!!!!!!!!!!! -! printout -!!!!!!!!!!!!!!!!!! - if (pr) then - call timer%write(6,'E+G') - if(abs(sum(nlist%q)-ichrg).gt.1.d-1) then ! check EEQ only once - write(env%unit,*) nlist%q - write(env%unit,*) sum(nlist%q),ichrg - call env%error('EEQ charge constrain error', source) - return - endif - r3 = 0 - do i=1,n - r3(:) = r3(:)+nlist%q(i)*xyz(:,i) - enddo - -! just for fit De calc - sqrab = 1.d+12 - srab = 1.d+6 - cn = 0 -! asymtotically for R=inf, Etot is the SIE contaminted EES -! which is computed here to get the atomization energy De,n,at(n) - call goed_gfnff(env,.true.,n,at,sqrab,srab,dfloat(ichrg),eeqtmp,cn,qtmp,eesinf,solvation,param,topo) - de=-(etot - eesinf) - endif -! write resusts to res type - res_gff%e_total = etot - res_gff%gnorm = sqrt(sum(g**2)) - res_gff%e_bond = ebond - res_gff%e_angl = eangl - res_gff%e_tors = etors - res_gff%e_es = ees - res_gff%e_rep = erep - res_gff%e_disp = edisp - res_gff%e_hb = ehb - res_gff%e_xb = exb - res_gff%e_batm = ebatm - res_gff%e_ext = eext - res_gff%g_hb = ghb - res_gff%g_born = gborn - res_gff%g_solv = gsolv - res_gff%g_shift = gshift - res_gff%g_sasa = gsasa - call mctc_gemv(xyz, nlist%q, res_gff%dipole) - - end subroutine gfnff_eg + ! write resusts to res type ! + res_gff%e_total = etot + res_gff%gnorm = sqrt(sum(g**2)) + res_gff%e_bond = ebond + res_gff%e_angl = eangl + res_gff%e_tors = etors + res_gff%e_es = ees + res_gff%e_rep = erep + res_gff%e_disp = edisp + res_gff%e_hb = ehb + res_gff%e_xb = exb + res_gff%e_batm = ebatm + res_gff%e_ext = eext + res_gff%g_hb = ghb + res_gff%g_born = gborn + res_gff%g_solv = gsolv + res_gff%g_shift = gshift + res_gff%g_sasa = gsasa + + call mctc_gemv(xyz, nlist%q, res_gff%dipole) + +end subroutine gfnff_eg !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egbond(i,iat,jat,rab,rij,drij,n,at,xyz,e,g,topo) - implicit none - !Dummy - type(TGFFTopology), intent(in) :: topo - integer,intent(in) :: i - integer,intent(in) :: n - integer,intent(in) :: iat - integer,intent(in) :: jat - integer,intent(in) :: at(n) - real*8,intent(in) :: rab - real*8,intent(in) :: rij - real*8,intent(in) :: drij(3,n) - real*8,intent(in) :: xyz(3,n) - real*8,intent(inout) :: e - real*8,intent(inout) :: g(3,n) - !Stack - integer j,k - real*8 dr,dum - real*8 dx,dy,dz - real*8 yy - real*8 t4,t5,t6,t8 - - t8 =topo%vbond(2,i) - dr =rab-rij - dum=topo%vbond(3,i)*exp(-t8*dr**2) - e=e+dum ! bond energy - yy=2.0d0*t8*dr*dum - dx=xyz(1,iat)-xyz(1,jat) - dy=xyz(2,iat)-xyz(2,jat) - dz=xyz(3,iat)-xyz(3,jat) - t4=-yy*(dx/rab-drij(1,iat)) - t5=-yy*(dy/rab-drij(2,iat)) - t6=-yy*(dz/rab-drij(3,iat)) - g(1,iat)=g(1,iat)+t4-drij(1,iat)*yy ! to avoid if in loop below - g(2,iat)=g(2,iat)+t5-drij(2,iat)*yy - g(3,iat)=g(3,iat)+t6-drij(3,iat)*yy - t4=-yy*(-dx/rab-drij(1,jat)) - t5=-yy*(-dy/rab-drij(2,jat)) - t6=-yy*(-dz/rab-drij(3,jat)) - g(1,jat)=g(1,jat)+t4-drij(1,jat)*yy ! to avoid if in loop below - g(2,jat)=g(2,jat)+t5-drij(2,jat)*yy - g(3,jat)=g(3,jat)+t6-drij(3,jat)*yy - do k=1,n !3B gradient - g(:,k)=g(:,k)+drij(:,k)*yy - enddo - - end subroutine egbond +subroutine egbond(i,iat,jat,rab,rij,drij,n,at,xyz,e,g,topo) + implicit none + + type(TGFFTopology), intent(in) :: topo + integer,intent(in) :: i + integer,intent(in) :: n + integer,intent(in) :: iat + integer,intent(in) :: jat + integer,intent(in) :: at(n) + real*8,intent(in) :: rab + real*8,intent(in) :: rij + real*8,intent(in) :: drij(3,n) + real*8,intent(in) :: xyz(3,n) + real*8,intent(inout) :: e + real*8,intent(inout) :: g(3,n) + + integer j,k + real*8 dr,dum + real*8 dx,dy,dz + real*8 yy + real*8 t4,t5,t6,t8 + + t8 =topo%vbond(2,i) + dr =rab-rij + dum=topo%vbond(3,i)*exp(-t8*dr**2) + e=e+dum ! bond energy + yy=2.0d0*t8*dr*dum + dx=xyz(1,iat)-xyz(1,jat) + dy=xyz(2,iat)-xyz(2,jat) + dz=xyz(3,iat)-xyz(3,jat) + t4=-yy*(dx/rab-drij(1,iat)) + t5=-yy*(dy/rab-drij(2,iat)) + t6=-yy*(dz/rab-drij(3,iat)) + g(1,iat)=g(1,iat)+t4-drij(1,iat)*yy ! to avoid if in loop below + g(2,iat)=g(2,iat)+t5-drij(2,iat)*yy + g(3,iat)=g(3,iat)+t6-drij(3,iat)*yy + t4=-yy*(-dx/rab-drij(1,jat)) + t5=-yy*(-dy/rab-drij(2,jat)) + t6=-yy*(-dz/rab-drij(3,jat)) + g(1,jat)=g(1,jat)+t4-drij(1,jat)*yy ! to avoid if in loop below + g(2,jat)=g(2,jat)+t5-drij(2,jat)*yy + g(3,jat)=g(3,jat)+t6-drij(3,jat)*yy + + do k=1,n !3B gradient + g(:,k)=g(:,k)+drij(:,k)*yy + enddo + +end subroutine egbond !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egbond_hb(i,iat,jat,rab,rij,drij,hb_cn,hb_dcn,n,at,xyz,e,g,param,topo) - implicit none - !Dummy - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer,intent(in) :: i - integer,intent(in) :: n - integer,intent(in) :: iat - integer,intent(in) :: jat - integer,intent(in) :: at(n) - real*8,intent(in) :: rab - real*8,intent(in) :: rij - real*8,intent(in) :: drij(3,n) - real*8,intent(in) :: xyz(3,n) - real*8,intent(in) :: hb_cn(n) - real*8,intent(in) :: hb_dcn(3,n,n) - real*8,intent(inout) :: e - real*8,intent(inout) :: g(3,n) - !Stack - integer j,k - integer jA,jH - integer hbH,hbB,hbA - real*8 dr,dum - real*8 dx,dy,dz - real*8 yy,zz - real*8 t1,t4,t5,t6,t8 - - if (at(iat).eq.1) then - hbH=iat - hbA=jat - else if (at(jat).eq.1) then - hbH=jat - hbA=iat - else - write(*,'(10x,"No H-atom found in this bond ",i0,1x,i0)') iat,jat - return - end if - - t1=1.0-param%vbond_scale - t8 =(-t1*hb_cn(hbH)+1.0)*topo%vbond(2,i) - dr =rab-rij - dum=topo%vbond(3,i)*exp(-t8*dr**2) - e=e+dum ! bond energy - yy=2.0d0*t8*dr*dum - dx=xyz(1,iat)-xyz(1,jat) - dy=xyz(2,iat)-xyz(2,jat) - dz=xyz(3,iat)-xyz(3,jat) - t4=-yy*(dx/rab-drij(1,iat)) - t5=-yy*(dy/rab-drij(2,iat)) - t6=-yy*(dz/rab-drij(3,iat)) - g(1,iat)=g(1,iat)+t4-drij(1,iat)*yy ! to avoid if in loop below - g(2,iat)=g(2,iat)+t5-drij(2,iat)*yy - g(3,iat)=g(3,iat)+t6-drij(3,iat)*yy - t4=-yy*(-dx/rab-drij(1,jat)) - t5=-yy*(-dy/rab-drij(2,jat)) - t6=-yy*(-dz/rab-drij(3,jat)) - g(1,jat)=g(1,jat)+t4-drij(1,jat)*yy ! to avoid if in loop below - g(2,jat)=g(2,jat)+t5-drij(2,jat)*yy - g(3,jat)=g(3,jat)+t6-drij(3,jat)*yy - do k=1,n !3B gradient - g(:,k)=g(:,k)+drij(:,k)*yy - end do - zz=dum*topo%vbond(2,i)*dr**2*t1 - do j=1,topo%bond_hb_nr !CN gradient - jH = topo%bond_hb_AH(2,j) - jA = topo%bond_hb_AH(1,j) - if (jH.eq.hbH.and.jA.eq.hbA) then - g(:,hbH)=g(:,hbH)+hb_dcn(:,hbH,hbH)*zz - do k=1,topo%bond_hb_Bn(j) - hbB = topo%bond_hb_B(k,j) - g(:,hbB)=g(:,hbB)-hb_dcn(:,hbB,hbH)*zz - end do - end if +subroutine egbond_hb(i,iat,jat,rab,rij,drij,hb_cn,hb_dcn,n,at,xyz,e,g,param,topo) + + implicit none + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer,intent(in) :: i + integer,intent(in) :: n + integer,intent(in) :: iat + integer,intent(in) :: jat + integer,intent(in) :: at(n) + real*8,intent(in) :: rab + real*8,intent(in) :: rij + real*8,intent(in) :: drij(3,n) + real*8,intent(in) :: xyz(3,n) + real*8,intent(in) :: hb_cn(n) + real*8,intent(in) :: hb_dcn(3,n,n) + real*8,intent(inout) :: e + real*8,intent(inout) :: g(3,n) + + integer j,k + integer jA,jH + integer hbH,hbB,hbA + real*8 dr,dum + real*8 dx,dy,dz + real*8 yy,zz + real*8 t1,t4,t5,t6,t8 + + if (at(iat).eq.1) then + hbH=iat + hbA=jat + else if (at(jat).eq.1) then + hbH=jat + hbA=iat + else + write(*,'(10x,"No H-atom found in this bond ",i0,1x,i0)') iat,jat + return + end if + + t1=1.0-param%vbond_scale + t8 =(-t1*hb_cn(hbH)+1.0)*topo%vbond(2,i) + dr =rab-rij + dum=topo%vbond(3,i)*exp(-t8*dr**2) + e=e+dum ! bond energy ! + yy=2.0d0*t8*dr*dum + dx=xyz(1,iat)-xyz(1,jat) + dy=xyz(2,iat)-xyz(2,jat) + dz=xyz(3,iat)-xyz(3,jat) + t4=-yy*(dx/rab-drij(1,iat)) + t5=-yy*(dy/rab-drij(2,iat)) + t6=-yy*(dz/rab-drij(3,iat)) + g(1,iat)=g(1,iat)+t4-drij(1,iat)*yy ! to avoid if in loop below ! + g(2,iat)=g(2,iat)+t5-drij(2,iat)*yy + g(3,iat)=g(3,iat)+t6-drij(3,iat)*yy + t4=-yy*(-dx/rab-drij(1,jat)) + t5=-yy*(-dy/rab-drij(2,jat)) + t6=-yy*(-dz/rab-drij(3,jat)) + g(1,jat)=g(1,jat)+t4-drij(1,jat)*yy ! to avoid if in loop below ! + g(2,jat)=g(2,jat)+t5-drij(2,jat)*yy + g(3,jat)=g(3,jat)+t6-drij(3,jat)*yy + do k=1,n ! 3B gradient ! + g(:,k)=g(:,k)+drij(:,k)*yy + end do + zz=dum*topo%vbond(2,i)*dr**2*t1 + do j=1,topo%bond_hb_nr ! CN gradient ! + jH = topo%bond_hb_AH(2,j) + jA = topo%bond_hb_AH(1,j) + if (jH.eq.hbH.and.jA.eq.hbA) then + g(:,hbH)=g(:,hbH)+hb_dcn(:,hbH,hbH)*zz + do k=1,topo%bond_hb_Bn(j) + hbB = topo%bond_hb_B(k,j) + g(:,hbB)=g(:,hbB)-hb_dcn(:,hbB,hbH)*zz end do + end if + end do - end subroutine egbond_hb - - subroutine dncoord_erf(nat,at,xyz,rcov,cn,dcn,thr,topo) - use xtb_mctc_accuracy, only : wp - implicit none - !Dummy - type(TGFFTopology), intent(in) :: topo - integer,intent(in) :: nat - integer,intent(in) :: at(nat) - real(wp),intent(in) :: xyz(3,nat) - real(wp),intent(in) :: rcov(:) - real(wp),intent(out) :: cn(nat) - real(wp),intent(out) :: dcn(3,nat,nat) - real(wp),intent(in),optional :: thr - real(wp) :: cn_thr - !Stack - integer :: i, j - integer :: lin,linAH - integer :: iat, jat - integer :: iA,jA,jH - integer :: ati, atj - real(wp) :: r, r2, rij(3) - real(wp) :: rcovij - real(wp) :: dtmp, tmp - real(wp),parameter :: hlfosqrtpi = 1.0_wp/1.77245385091_wp - real(wp),parameter :: kn=27.5_wp - real(wp),parameter :: rcov_scal=1.78 - - cn = 0._wp - dcn = 0._wp - - do i = 1,topo%bond_hb_nr - iat = topo%bond_hb_AH(2,i) - ati = at(iat) - iA = topo%bond_hb_AH(1,i) - do j = 1, topo%bond_hb_Bn(i) - jat = topo%bond_hb_B(j,i) - atj = at(jat) - rij = xyz(:,jat) - xyz(:,iat) - r2 = sum( rij**2 ) - if (r2.gt.thr) cycle - r = sqrt(r2) - rcovij=rcov_scal*(rcov(ati)+rcov(atj)) - tmp = 0.5_wp * (1.0_wp + erf(-kn*(r-rcovij)/rcovij)) - dtmp =-hlfosqrtpi*kn*exp(-kn**2*(r-rcovij)**2/rcovij**2)/rcovij - cn(iat) = cn(iat) + tmp - cn(jat) = cn(jat) + tmp - dcn(:,jat,jat)= dtmp*rij/r + dcn(:,jat,jat) - dcn(:,iat,jat)= dtmp*rij/r - dcn(:,jat,iat)=-dtmp*rij/r - dcn(:,iat,iat)=-dtmp*rij/r + dcn(:,iat,iat) - end do - end do +end subroutine egbond_hb - end subroutine dncoord_erf +subroutine dncoord_erf(nat,at,xyz,rcov,cn,dcn,thr,topo) + + use xtb_mctc_accuracy, only : wp + + implicit none + + type(TGFFTopology), intent(in) :: topo + integer,intent(in) :: nat + integer,intent(in) :: at(nat) + real(wp),intent(in) :: xyz(3,nat) + real(wp),intent(in) :: rcov(:) + real(wp),intent(out) :: cn(nat) + real(wp),intent(out) :: dcn(3,nat,nat) + real(wp),intent(in),optional :: thr + real(wp) :: cn_thr + + integer :: i, j + integer :: lin,linAH + integer :: iat, jat + integer :: iA,jA,jH + integer :: ati, atj + real(wp) :: r, r2, rij(3) + real(wp) :: rcovij + real(wp) :: dtmp, tmp + real(wp),parameter :: hlfosqrtpi = 1.0_wp/1.77245385091_wp + real(wp),parameter :: kn=27.5_wp + real(wp),parameter :: rcov_scal=1.78 + + cn = 0._wp + dcn = 0._wp + + do i = 1,topo%bond_hb_nr + iat = topo%bond_hb_AH(2,i) + ati = at(iat) + iA = topo%bond_hb_AH(1,i) + do j = 1, topo%bond_hb_Bn(i) + jat = topo%bond_hb_B(j,i) + atj = at(jat) + rij = xyz(:,jat) - xyz(:,iat) + r2 = sum( rij**2 ) + if (r2.gt.thr) cycle + r = sqrt(r2) + rcovij=rcov_scal*(rcov(ati)+rcov(atj)) + tmp = 0.5_wp * (1.0_wp + erf(-kn*(r-rcovij)/rcovij)) + dtmp =-hlfosqrtpi*kn*exp(-kn**2*(r-rcovij)**2/rcovij**2)/rcovij + cn(iat) = cn(iat) + tmp + cn(jat) = cn(jat) + tmp + dcn(:,jat,jat)= dtmp*rij/r + dcn(:,jat,jat) + dcn(:,iat,jat)= dtmp*rij/r + dcn(:,jat,iat)=-dtmp*rij/r + dcn(:,iat,iat)=-dtmp*rij/r + dcn(:,iat,iat) + end do + end do + +end subroutine dncoord_erf !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egbend(m,j,i,k,n,at,xyz,e,g,param,topo) - use xtb_mctc_constants - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer m,n,at(n) - integer i,j,k - real*8 xyz(3,n),g(3,3),e - - real*8 c0,kijk,va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff,rn - - c0 =topo%vangl(1,m) - kijk=topo%vangl(2,m) - va(1:3) = xyz(1:3,i) - vb(1:3) = xyz(1:3,j) - vc(1:3) = xyz(1:3,k) - call vsub(va,vb,vab,3) - call vsub(vc,vb,vcb,3) - rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - call crprod(vcb,vab,vp) - rp = vlen(vp)+1.d-14 - call impsc(vab,vcb,cosa) - cosa = dble(min(1.0d0,max(-1.0d0,cosa))) - theta= dacos(cosa) - - call gfnffdampa(at(i),at(j),rab2,dampij,damp2ij,param) - call gfnffdampa(at(k),at(j),rcb2,dampjk,damp2jk,param) - damp=dampij*dampjk - - if(pi-c0.lt.1.d-6)then ! linear - dt = theta - c0 - ea = kijk * dt**2 - deddt = 2.d0 * kijk * dt - else - ea=kijk*(cosa-cos(c0))**2 - deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) - endif +subroutine egbend(m,j,i,k,n,at,xyz,e,g,param,topo) + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer m,n,at(n) + integer i,j,k + real*8 xyz(3,n),g(3,3),e + + real*8 c0,kijk,va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff,rn + + c0 =topo%vangl(1,m) + kijk=topo%vangl(2,m) + va(1:3) = xyz(1:3,i) + vb(1:3) = xyz(1:3,j) + vc(1:3) = xyz(1:3,k) + call vsub(va,vb,vab,3) + call vsub(vc,vb,vcb,3) + rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + call crprod(vcb,vab,vp) + rp = vlen(vp)+1.d-14 + call impsc(vab,vcb,cosa) + cosa = dble(min(1.0d0,max(-1.0d0,cosa))) + theta= dacos(cosa) + + call gfnffdampa(at(i),at(j),rab2,dampij,damp2ij,param) + call gfnffdampa(at(k),at(j),rcb2,dampjk,damp2jk,param) + damp=dampij*dampjk + + if (pi-c0.lt.1.d-6) then ! linear ! + dt = theta - c0 + ea = kijk * dt**2 + deddt = 2.d0 * kijk * dt + else + ea=kijk*(cosa-cos(c0))**2 + deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) + endif - e = ea * damp - call crprod(vab,vp,deda) - rmul1 = -deddt / (rab2*rp) - deda = deda*rmul1 - call crprod(vcb,vp,dedc) - rmul2 = deddt / (rcb2*rp) - dedc = dedc*rmul2 - dedb = deda+dedc - term1(1:3)=ea*damp2ij*dampjk*vab(1:3) - term2(1:3)=ea*damp2jk*dampij*vcb(1:3) - g(1:3,1) = -dedb(1:3)*damp-term1(1:3)-term2(1:3) - g(1:3,2) = deda(1:3)*damp+term1(1:3) - g(1:3,3) = dedc(1:3)*damp+term2(1:3) - - end subroutine egbend + e = ea * damp + call crprod(vab,vp,deda) + rmul1 = -deddt / (rab2*rp) + deda = deda*rmul1 + call crprod(vcb,vp,dedc) + rmul2 = deddt / (rcb2*rp) + dedc = dedc*rmul2 + dedb = deda+dedc + term1(1:3)=ea*damp2ij*dampjk*vab(1:3) + term2(1:3)=ea*damp2jk*dampij*vcb(1:3) + g(1:3,1) = -dedb(1:3)*damp-term1(1:3)-term2(1:3) + g(1:3,2) = deda(1:3)*damp+term1(1:3) + g(1:3,3) = dedc(1:3)*damp+term2(1:3) + +end subroutine egbend !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egbend_nci_mul(j,i,k,c0,fc,n,at,xyz,e,g) - use xtb_mctc_constants - implicit none - !Dummy - integer n,at(n) - integer i,j,k - real*8 c0,fc - real*8 xyz(3,n),g(3,3),e - !Stack - real*8 kijk,va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff,rn - - kijk=fc/(cos(0.0d0)-cos(c0))**2 - va(1:3) = xyz(1:3,i) - vb(1:3) = xyz(1:3,j) - vc(1:3) = xyz(1:3,k) - call vsub(va,vb,vab,3) - call vsub(vc,vb,vcb,3) - rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - call crprod(vcb,vab,vp) - rp = vlen(vp)+1.d-14 - call impsc(vab,vcb,cosa) - cosa = dble(min(1.0d0,max(-1.0d0,cosa))) - theta= dacos(cosa) - - if(pi-c0.lt.1.d-6)then ! linear - dt = theta - c0 - ea = kijk * dt**2 - deddt = 2.d0 * kijk * dt - else - ea=kijk*(cosa-cos(c0))**2 ! not linear - deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) - endif - - e = (1.0d0-ea) - call crprod(vab,vp,deda) - rmul1 = -deddt / (rab2*rp) - deda = deda*rmul1 - call crprod(vcb,vp,dedc) - rmul2 = deddt / (rcb2*rp) - dedc = dedc*rmul2 - dedb = deda+dedc - g(1:3,1) = dedb(1:3) - g(1:3,2) = -deda(1:3) - g(1:3,3) = -dedc(1:3) +subroutine egbend_nci_mul(j,i,k,c0,fc,n,at,xyz,e,g) + + use xtb_mctc_constants + implicit none + + integer n,at(n) + integer i,j,k + real*8 c0,fc + real*8 xyz(3,n),g(3,3),e + + real*8 kijk,va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff,rn + + kijk=fc/(cos(0.0d0)-cos(c0))**2 + va(1:3) = xyz(1:3,i) + vb(1:3) = xyz(1:3,j) + vc(1:3) = xyz(1:3,k) + call vsub(va,vb,vab,3) + call vsub(vc,vb,vcb,3) + rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + call crprod(vcb,vab,vp) + rp = vlen(vp)+1.d-14 + call impsc(vab,vcb,cosa) + cosa = dble(min(1.0d0,max(-1.0d0,cosa))) + theta= dacos(cosa) + + ! linear ! + if(pi-c0.lt.1.d-6)then + dt = theta - c0 + ea = kijk * dt**2 + deddt = 2.d0 * kijk * dt + + ! not linear ! + else + ea=kijk*(cosa-cos(c0))**2 + deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) + endif - end subroutine egbend_nci_mul + e = (1.0d0-ea) + call crprod(vab,vp,deda) + rmul1 = -deddt / (rab2*rp) + deda = deda*rmul1 + call crprod(vcb,vp,dedc) + rmul2 = deddt / (rcb2*rp) + dedc = dedc*rmul2 + dedb = deda+dedc + + g(1:3,1) = dedb(1:3) + g(1:3,2) = -deda(1:3) + g(1:3,3) = -dedc(1:3) + +end subroutine egbend_nci_mul !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egbend_nci(j,i,k,c0,kijk,n,at,xyz,e,g,param) - use xtb_mctc_constants - implicit none - !Dummy - type(TGFFData), intent(in) :: param - integer n,at(n) - integer i,j,k - real*8 c0,kijk - real*8 xyz(3,n),g(3,3),e - !Stack - real*8 va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff,rn - - va(1:3) = xyz(1:3,i) - vb(1:3) = xyz(1:3,j) - vc(1:3) = xyz(1:3,k) - call vsub(va,vb,vab,3) - call vsub(vc,vb,vcb,3) - rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - call crprod(vcb,vab,vp) - rp = vlen(vp)+1.d-14 - call impsc(vab,vcb,cosa) - cosa = dble(min(1.0d0,max(-1.0d0,cosa))) - theta= dacos(cosa) - - call gfnffdampa_nci(at(i),at(j),rab2,dampij,damp2ij,param) - call gfnffdampa_nci(at(k),at(j),rcb2,dampjk,damp2jk,param) - damp=dampij*dampjk - - if(pi-c0.lt.1.d-6)then ! linear - dt = theta - c0 - ea = kijk * dt**2 - deddt = 2.d0 * kijk * dt - else - ea=kijk*(cosa-cos(c0))**2 - deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) - endif +subroutine egbend_nci(j,i,k,c0,kijk,n,at,xyz,e,g,param) + + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + integer n,at(n) + integer i,j,k + real*8 c0,kijk + real*8 xyz(3,n),g(3,3),e + + real*8 va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff,rn + + va(1:3) = xyz(1:3,i) + vb(1:3) = xyz(1:3,j) + vc(1:3) = xyz(1:3,k) + call vsub(va,vb,vab,3) + call vsub(vc,vb,vcb,3) + rab2 = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rcb2 = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + call crprod(vcb,vab,vp) + rp = vlen(vp)+1.d-14 + call impsc(vab,vcb,cosa) + cosa = dble(min(1.0d0,max(-1.0d0,cosa))) + theta= dacos(cosa) + + call gfnffdampa_nci(at(i),at(j),rab2,dampij,damp2ij,param) + call gfnffdampa_nci(at(k),at(j),rcb2,dampjk,damp2jk,param) + damp=dampij*dampjk + + ! linear ! + if(pi-c0.lt.1.d-6)then + dt = theta - c0 + ea = kijk * dt**2 + deddt = 2.d0 * kijk * dt + else + ea=kijk*(cosa-cos(c0))**2 + deddt=2.0d0*kijk*sin(theta)*(cos(c0)-cosa) + endif - e = ea * damp - call crprod(vab,vp,deda) - rmul1 = -deddt / (rab2*rp) - deda = deda*rmul1 - call crprod(vcb,vp,dedc) - rmul2 = deddt / (rcb2*rp) - dedc = dedc*rmul2 - dedb = deda+dedc - term1(1:3)=ea*damp2ij*dampjk*vab(1:3) - term2(1:3)=ea*damp2jk*dampij*vcb(1:3) - g(1:3,1) = -dedb(1:3)*damp-term1(1:3)-term2(1:3) - g(1:3,2) = deda(1:3)*damp+term1(1:3) - g(1:3,3) = dedc(1:3)*damp+term2(1:3) - - end subroutine egbend_nci + e = ea * damp + call crprod(vab,vp,deda) + rmul1 = -deddt / (rab2*rp) + deda = deda*rmul1 + call crprod(vcb,vp,dedc) + rmul2 = deddt / (rcb2*rp) + dedc = dedc*rmul2 + dedb = deda+dedc + term1(1:3)=ea*damp2ij*dampjk*vab(1:3) + term2(1:3)=ea*damp2jk*dampij*vcb(1:3) + + g(1:3,1) = -dedb(1:3)*damp-term1(1:3)-term2(1:3) + g(1:3,2) = deda(1:3)*damp+term1(1:3) + g(1:3,3) = dedc(1:3)*damp+term2(1:3) + +end subroutine egbend_nci !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine egtors(m,i,j,k,l,n,at,xyz,e,g,param,topo) - use xtb_mctc_constants - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer m,n,at(n) - integer i,j,k,l - real*8 xyz(3,n),g(3,4),e - - real*8 c0,kijk,va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff,rn - - rn=dble(topo%tlist(5,m)) - phi0 =topo%vtors(1,m) - if(topo%tlist(5,m).gt.0)then - vab(1:3) = xyz(1:3,i)-xyz(1:3,j) - vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) - vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) - rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) - call gfnffdampt(at(i),at(j),rij,dampij,damp2ij,param) - call gfnffdampt(at(k),at(j),rjk,dampjk,damp2jk,param) - call gfnffdampt(at(k),at(l),rkl,dampkl,damp2kl,param) - damp= dampjk*dampij*dampkl - phi=valijklff(n,xyz,i,j,k,l) - call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) - dphi1=phi-phi0 - c1=rn*dphi1+pi - x1cos=cos(c1) - x1sin=sin(c1) - et =(1.+x1cos)*topo%vtors(2,m) - dij=-rn*x1sin*topo%vtors(2,m)*damp - term1(1:3)=et*damp2ij*dampjk*dampkl*vab(1:3) - term2(1:3)=et*damp2jk*dampij*dampkl*vcb(1:3) - term3(1:3)=et*damp2kl*dampij*dampjk*vdc(1:3) - g(1:3,1)=dij*dda(1:3)+term1 - g(1:3,2)=dij*ddb(1:3)-term1+term2 - g(1:3,3)=dij*ddc(1:3)+term3-term2 - g(1:3,4)=dij*ddd(1:3)-term3 - e=et*damp - else - vab(1:3) = xyz(1:3,j)-xyz(1:3,i) - vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) - vdc(1:3) = xyz(1:3,j)-xyz(1:3,l) - rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - rjl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) - call gfnffdampt(at(i),at(j),rij,dampij,damp2ij,param) - call gfnffdampt(at(k),at(j),rjk,dampjk,damp2jk,param) - call gfnffdampt(at(j),at(l),rjl,dampjl,damp2jl,param) - damp= dampjk*dampij*dampjl - phi=omega(n,xyz,i,j,k,l) - call domegadr(n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) - if(topo%tlist(5,m).eq.0)then ! phi0=0 case +subroutine egtors(m,i,j,k,l,n,at,xyz,e,g,param,topo) + + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer m,n,at(n) + integer i,j,k,l + real*8 xyz(3,n),g(3,4),e + + real*8 c0,kijk,va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,phi0,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff,rn + + rn=dble(topo%tlist(5,m)) + phi0 =topo%vtors(1,m) + + if(topo%tlist(5,m).gt.0)then + vab(1:3) = xyz(1:3,i)-xyz(1:3,j) + vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) + vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) + rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) + call gfnffdampt(at(i),at(j),rij,dampij,damp2ij,param) + call gfnffdampt(at(k),at(j),rjk,dampjk,damp2jk,param) + call gfnffdampt(at(k),at(l),rkl,dampkl,damp2kl,param) + damp= dampjk*dampij*dampkl + phi=valijklff(n,xyz,i,j,k,l) + call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) + dphi1=phi-phi0 + c1=rn*dphi1+pi + x1cos=cos(c1) + x1sin=sin(c1) + et =(1.+x1cos)*topo%vtors(2,m) + dij=-rn*x1sin*topo%vtors(2,m)*damp + term1(1:3)=et*damp2ij*dampjk*dampkl*vab(1:3) + term2(1:3)=et*damp2jk*dampij*dampkl*vcb(1:3) + term3(1:3)=et*damp2kl*dampij*dampjk*vdc(1:3) + g(1:3,1)=dij*dda(1:3)+term1 + g(1:3,2)=dij*ddb(1:3)-term1+term2 + g(1:3,3)=dij*ddc(1:3)+term3-term2 + g(1:3,4)=dij*ddd(1:3)-term3 + e=et*damp + else + vab(1:3) = xyz(1:3,j)-xyz(1:3,i) + vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) + vdc(1:3) = xyz(1:3,j)-xyz(1:3,l) + rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + rjl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) + call gfnffdampt(at(i),at(j),rij,dampij,damp2ij,param) + call gfnffdampt(at(k),at(j),rjk,dampjk,damp2jk,param) + call gfnffdampt(at(j),at(l),rjl,dampjl,damp2jl,param) + damp= dampjk*dampij*dampjl + phi=omega(n,xyz,i,j,k,l) + call domegadr(n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) + + ! phi0=0 case ! + if(topo%tlist(5,m).eq.0)then dphi1=phi-phi0 c1=dphi1+pi x1cos=cos(c1) x1sin=sin(c1) et =(1.+x1cos)*topo%vtors(2,m) dij =-x1sin*topo%vtors(2,m)*damp - else ! double min at phi0,-phi0 + ! double min at phi0,-phi0 ! + else et = topo%vtors(2,m)*(cos(phi) -cos(phi0))**2 dij=2.*topo%vtors(2,m)* sin(phi)*(cos(phi0)-cos(phi))*damp - endif - term1(1:3)=et*damp2ij*dampjk*dampjl*vab(1:3) - term2(1:3)=et*damp2jk*dampij*dampjl*vcb(1:3) - term3(1:3)=et*damp2jl*dampij*dampjk*vdc(1:3) - g(1:3,1)=dij*dda(1:3)-term1 - g(1:3,2)=dij*ddb(1:3)+term1+term2+term3 - g(1:3,3)=dij*ddc(1:3)-term2 - g(1:3,4)=dij*ddd(1:3)-term3 - e=et*damp - endif + endif + + term1(1:3)=et*damp2ij*dampjk*dampjl*vab(1:3) + term2(1:3)=et*damp2jk*dampij*dampjl*vcb(1:3) + term3(1:3)=et*damp2jl*dampij*dampjk*vdc(1:3) + + g(1:3,1)=dij*dda(1:3)-term1 + g(1:3,2)=dij*ddb(1:3)+term1+term2+term3 + g(1:3,3)=dij*ddc(1:3)-term2 + g(1:3,4)=dij*ddd(1:3)-term3 + + e=et*damp + endif - end subroutine egtors +end subroutine egtors !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !torsion without distance damping!!! damping is inherint in the HB term - subroutine egtors_nci_mul(i,j,k,l,rn,phi0,tshift,n,at,xyz,e,g) - use xtb_mctc_constants - implicit none - !Dummy - integer n,at(n) - integer i,j,k,l - integer rn - real*8 phi0,tshift - real*8 xyz(3,n),g(3,4),e - !Stack - real*8 c0,fc,kijk,va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff - - fc=(1.0d0-tshift)/2.0d0 - vab(1:3) = xyz(1:3,i)-xyz(1:3,j) - vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) - vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) - rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) - phi=valijklff(n,xyz,i,j,k,l) - call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) - dphi1=phi-phi0 - c1=rn*dphi1+pi - x1cos=cos(c1) - x1sin=sin(c1) - et =(1.+x1cos)*fc+tshift - dij=-rn*x1sin*fc - g(1:3,1)=dij*dda(1:3) - g(1:3,2)=dij*ddb(1:3) - g(1:3,3)=dij*ddc(1:3) - g(1:3,4)=dij*ddd(1:3) - e=et !*damp - end subroutine egtors_nci_mul - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - subroutine egtors_nci(i,j,k,l,rn,phi0,fc,n,at,xyz,e,g,param) - use xtb_mctc_constants - implicit none - !Dummy - type(TGFFData), intent(in) :: param - integer n,at(n) - integer i,j,k,l - integer rn - real*8 phi0,fc - real*8 xyz(3,n),g(3,4),e - !Stack - real*8 c0,kijk,va(3),vb(3),vc(3),cosa - real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt - real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp - real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk - real*8 theta,deda(3),vlen,vp(3),et,dij,c1 - real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) - real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi - real*8 omega,rij,rijk,rkl,rjk,dampkl,damp2kl - real*8 dampjl,damp2jl,valijklff - - vab(1:3) = xyz(1:3,i)-xyz(1:3,j) - vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) - vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) - rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) - rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) - rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) - call gfnffdampt_nci(at(i),at(j),rij,dampij,damp2ij,param) - call gfnffdampt_nci(at(k),at(j),rjk,dampjk,damp2jk,param) - call gfnffdampt_nci(at(k),at(l),rkl,dampkl,damp2kl,param) - damp= dampjk*dampij*dampkl - phi=valijklff(n,xyz,i,j,k,l) - call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) - dphi1=phi-phi0 - c1=rn*dphi1+pi - x1cos=cos(c1) - x1sin=sin(c1) - et =(1.+x1cos)*fc - dij=-rn*x1sin*fc*damp - term1(1:3)=et*damp2ij*dampjk*dampkl*vab(1:3) - term2(1:3)=et*damp2jk*dampij*dampkl*vcb(1:3) - term3(1:3)=et*damp2kl*dampij*dampjk*vdc(1:3) - g(1:3,1)=dij*dda(1:3)+term1 - g(1:3,2)=dij*ddb(1:3)-term1+term2 - g(1:3,3)=dij*ddc(1:3)+term3-term2 - g(1:3,4)=dij*ddd(1:3)-term3 - e=et*damp - end subroutine egtors_nci +!> torsion without distance damping !!! damping is inherint in the HB term +subroutine egtors_nci_mul(i,j,k,l,rn,phi0,tshift,n,at,xyz,e,g) + + use xtb_mctc_constants + implicit none + + integer n,at(n) + integer i,j,k,l + integer rn + real*8 phi0,tshift + real*8 xyz(3,n),g(3,4),e + + real*8 c0,fc,kijk,va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff + + fc=(1.0d0-tshift)/2.0d0 + vab(1:3) = xyz(1:3,i)-xyz(1:3,j) + vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) + vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) + rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) + phi=valijklff(n,xyz,i,j,k,l) + call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) + dphi1=phi-phi0 + c1=rn*dphi1+pi + x1cos=cos(c1) + x1sin=sin(c1) + et =(1.+x1cos)*fc+tshift + dij=-rn*x1sin*fc + g(1:3,1)=dij*dda(1:3) + g(1:3,2)=dij*ddb(1:3) + g(1:3,3)=dij*ddc(1:3) + g(1:3,4)=dij*ddd(1:3) + e=et ! *damp ! + +end subroutine egtors_nci_mul + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +subroutine egtors_nci(i,j,k,l,rn,phi0,fc,n,at,xyz,e,g,param) + + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + integer n,at(n) + integer i,j,k,l + integer rn + real*8 phi0,fc + real*8 xyz(3,n),g(3,4),e + + real*8 c0,kijk,va(3),vb(3),vc(3),cosa + real*8 dt,ea,dedb(3),dedc(3),rmul2,rmul1,deddt + real*8 term1(3),term2(3),rab2,vab(3),vcb(3),rp + real*8 rcb2,damp,dampij,damp2ij,dampjk,damp2jk + real*8 theta,deda(3),vlen,vp(3),et,dij,c1 + real*8 term3(3),x1sin,x1cos,e1,dphi1,vdc(3) + real*8 ddd(3),ddc(3),ddb(3),dda(3),rjl,phi + real*8 omega,rij,rijk,rkl,rjk,dampkl,damp2kl + real*8 dampjl,damp2jl,valijklff + + vab(1:3) = xyz(1:3,i)-xyz(1:3,j) + vcb(1:3) = xyz(1:3,j)-xyz(1:3,k) + vdc(1:3) = xyz(1:3,k)-xyz(1:3,l) + + rij = vab(1)*vab(1) + vab(2)*vab(2) + vab(3)*vab(3) + rjk = vcb(1)*vcb(1) + vcb(2)*vcb(2) + vcb(3)*vcb(3) + rkl = vdc(1)*vdc(1) + vdc(2)*vdc(2) + vdc(3)*vdc(3) + + call gfnffdampt_nci(at(i),at(j),rij,dampij,damp2ij,param) + call gfnffdampt_nci(at(k),at(j),rjk,dampjk,damp2jk,param) + call gfnffdampt_nci(at(k),at(l),rkl,dampkl,damp2kl,param) + + damp= dampjk*dampij*dampkl + phi=valijklff(n,xyz,i,j,k,l) + + call dphidr (n,xyz,i,j,k,l,phi,dda,ddb,ddc,ddd) + + dphi1=phi-phi0 + c1=rn*dphi1+pi + x1cos=cos(c1) + x1sin=sin(c1) + et =(1.+x1cos)*fc + dij=-rn*x1sin*fc*damp + + term1(1:3)=et*damp2ij*dampjk*dampkl*vab(1:3) + term2(1:3)=et*damp2jk*dampij*dampkl*vcb(1:3) + term3(1:3)=et*damp2kl*dampij*dampjk*vdc(1:3) + + g(1:3,1)=dij*dda(1:3)+term1 + g(1:3,2)=dij*ddb(1:3)-term1+term2 + g(1:3,3)=dij*ddc(1:3)+term3-term2 + g(1:3,4)=dij*ddd(1:3)-term3 + + e=et*damp + +end subroutine egtors_nci !cccccccccccccccccccccccccccccccccccccccccccccc ! damping of bend and torsion for long ! bond distances to allow proper dissociation !cccccccccccccccccccccccccccccccccccccccccccccc - subroutine gfnffdampa(ati,atj,r2,damp,ddamp,param) - implicit none - type(TGFFData), intent(in) :: param - integer ati,atj - real*8 r2,damp,ddamp,rr,rcut - rcut =param%atcuta*(param%rcov(ati)+param%rcov(atj))**2 - rr =(r2/rcut)**2 - damp = 1.0d0/(1.0d0+rr) - ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) - end subroutine gfnffdampa - - subroutine gfnffdampt(ati,atj,r2,damp,ddamp,param) - implicit none - type(TGFFData), intent(in) :: param - integer ati,atj - real*8 r2,damp,ddamp,rr,rcut - rcut =param%atcutt*(param%rcov(ati)+param%rcov(atj))**2 - rr =(r2/rcut)**2 - damp = 1.0d0/(1.0d0+rr) - ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) - end subroutine gfnffdampt - - subroutine gfnffdampa_nci(ati,atj,r2,damp,ddamp,param) - implicit none - type(TGFFData), intent(in) :: param - integer ati,atj - real*8 r2,damp,ddamp,rr,rcut - rcut =param%atcuta_nci*(param%rcov(ati)+param%rcov(atj))**2 - rr =(r2/rcut)**2 - damp = 1.0d0/(1.0d0+rr) - ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) - end subroutine gfnffdampa_nci - - subroutine gfnffdampt_nci(ati,atj,r2,damp,ddamp,param) - implicit none - type(TGFFData), intent(in) :: param - integer ati,atj - real*8 r2,damp,ddamp,rr,rcut - rcut =param%atcutt_nci*(param%rcov(ati)+param%rcov(atj))**2 - rr =(r2/rcut)**2 - damp = 1.0d0/(1.0d0+rr) - ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) - end subroutine gfnffdampt_nci +subroutine gfnffdampa(ati,atj,r2,damp,ddamp,param) + + implicit none + type(TGFFData), intent(in) :: param + integer ati,atj + real*8 r2,damp,ddamp,rr,rcut + + rcut =param%atcuta*(param%rcov(ati)+param%rcov(atj))**2 + rr =(r2/rcut)**2 + damp = 1.0d0/(1.0d0+rr) + ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) + +end subroutine gfnffdampa + +subroutine gfnffdampt(ati,atj,r2,damp,ddamp,param) + + implicit none + type(TGFFData), intent(in) :: param + integer ati,atj + real*8 r2,damp,ddamp,rr,rcut + + rcut =param%atcutt*(param%rcov(ati)+param%rcov(atj))**2 + rr =(r2/rcut)**2 + damp = 1.0d0/(1.0d0+rr) + ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) + +end subroutine gfnffdampt + +subroutine gfnffdampa_nci(ati,atj,r2,damp,ddamp,param) + + implicit none + type(TGFFData), intent(in) :: param + integer ati,atj + real*8 r2,damp,ddamp,rr,rcut + + rcut =param%atcuta_nci*(param%rcov(ati)+param%rcov(atj))**2 + rr =(r2/rcut)**2 + damp = 1.0d0/(1.0d0+rr) + ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) + +end subroutine gfnffdampa_nci + +subroutine gfnffdampt_nci(ati,atj,r2,damp,ddamp,param) + + implicit none + type(TGFFData), intent(in) :: param + integer ati,atj + real*8 r2,damp,ddamp,rr,rcut + + rcut =param%atcutt_nci*(param%rcov(ati)+param%rcov(atj))**2 + rr =(r2/rcut)**2 + damp = 1.0d0/(1.0d0+rr) + ddamp=-2.d0*2*rr/(r2*(1.0d0+rr)**2) + +end subroutine gfnffdampt_nci !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Ref.: S. Alireza Ghasemi, Albert Hofstetter, Santanu Saha, and Stefan Goedecker @@ -1260,2043 +1336,2169 @@ end subroutine gfnffdampt_nci ! based on charge densities obtained by a neural network !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine goed_gfnff(env,single,n,at,sqrab,r,chrg,eeqtmp,cn,q,es,gbsa,param,topo) - use xtb_mctc_accuracy, only : wp, sp - use xtb_mctc_la - implicit none - character(len=*), parameter :: source = 'gfnff_eg_goed' - type(TEnvironment), intent(inout) :: env - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - logical, intent(in) :: single ! real*4 flag for solver - integer, intent(in) :: n ! number of atoms - integer, intent(in) :: at(n) ! ordinal numbers - real(wp),intent(in) :: sqrab(n*(n+1)/2) ! squared dist - real(wp),intent(in) :: r(n*(n+1)/2) ! dist - real(wp),intent(in) :: chrg ! total charge on system - real(wp),intent(in) :: cn(n) ! CN - real(wp),intent(out) :: q(n) ! output charges - real(wp),intent(out) :: es ! ES energy - real(wp),intent(out) :: eeqtmp(2,n*(n+1)/2) ! intermediates - type(TBorn), allocatable, intent(in) :: gbsa - -! local variables - integer :: m,i,j,k,ii,ij - integer,allocatable :: ipiv(:) - real(wp) :: gammij,tsqrt2pi,r2,tmp - real(wp),allocatable :: A (:,:),x (:) - real(sp),allocatable :: A4(:,:),x4(:) -! parameter - parameter (tsqrt2pi = 0.797884560802866_wp) - logical :: exitRun - - m=n+topo%nfrag ! # atoms + chrg constrain + frag constrain - - allocate(A(m,m),x(m)) -! setup RHS - do i=1,n - x(i) = topo%chieeq(i) + param%cnf(at(i))*sqrt(cn(i)) - enddo - - A = 0 -! setup A matrix -!$omp parallel default(none) & -!$omp shared(topo,n,sqrab,r,eeqtmp,A,at) & -!$omp private(i,j,k,ij,gammij,tmp) -!$omp do schedule(dynamic) - do i=1,n - A(i,i)=tsqrt2pi/sqrt(topo%alpeeq(i))+topo%gameeq(i) ! J of i +subroutine goed_gfnff(env,single,n,at,sqrab,r,chrg,eeqtmp,cn,q,es,gbsa,param,topo) + + use xtb_mctc_accuracy, only : wp, sp + use xtb_mctc_la + implicit none + + character(len=*), parameter :: source = 'gfnff_eg_goed' + type(TEnvironment), intent(inout) :: env + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + + !> real*4 flag for solver + logical, intent(in) :: single + + !> number of atoms + integer, intent(in) :: n + + !> ordinal numbers + integer, intent(in) :: at(n) + + !> squared dist + real(wp),intent(in) :: sqrab(n*(n+1)/2) + + !> distance + real(wp),intent(in) :: r(n*(n+1)/2) + + !> total charge + real(wp),intent(in) :: chrg + + !> coordination number + real(wp),intent(in) :: cn(n) + + !> output charges + real(wp),intent(out) :: q(n) + + !> ES term + real(wp),intent(out) :: es + + !>intermediates + real(wp),intent(out) :: eeqtmp(2,n*(n+1)/2) + + !> Solvation + type(TBorn), allocatable, intent(in) :: gbsa + + integer :: m,i,j,k,ii,ij + integer,allocatable :: ipiv(:) + real(wp) :: gammij,tsqrt2pi,r2,tmp + real(wp),allocatable :: A (:,:),x (:) + real(sp),allocatable :: A4(:,:),x4(:) + parameter (tsqrt2pi = 0.797884560802866_wp) + logical :: exitRun + + ! # atoms + chrg constrain + frag constrain ! + m=n+topo%nfrag + allocate(A(m,m),x(m)) + + ! setup RHS ! + + do i=1,n + x(i) = topo%chieeq(i) + param%cnf(at(i))*sqrt(cn(i)) + enddo + + A = 0 + + ! setup A matrix ! + + !$omp parallel default(none) & + !$omp shared(topo,n,sqrab,r,eeqtmp,A,at) & + !$omp private(i,j,k,ij,gammij,tmp) + !$omp do schedule(dynamic) + do i=1,n + + A(i,i)=tsqrt2pi/sqrt(topo%alpeeq(i))+topo%gameeq(i) ! J of i ! k = i*(i-1)/2 + do j=1,i-1 + ij = k+j - gammij=1./sqrt(topo%alpeeq(i)+topo%alpeeq(j)) ! squared above + gammij=1./sqrt(topo%alpeeq(i)+topo%alpeeq(j)) ! squared above ! tmp = erf(gammij*r(ij)) eeqtmp(1,ij)=gammij eeqtmp(2,ij)=tmp A(j,i) = tmp/r(ij) A(i,j) = A(j,i) + enddo - enddo -!$omp enddo -!$omp end parallel - -! fragment charge constrain - do i=1,topo%nfrag - x(n+i)=topo%qfrag(i) - do j=1,n + enddo + !$omp enddo + !$omp end parallel + + ! fragment charge constrain ! + + do i=1,topo%nfrag + x(n+i)=topo%qfrag(i) + do j=1,n if(topo%fraglist(j).eq.i) then A(n+i,j)=1 A(j,n+i)=1 endif - enddo enddo + enddo - if (allocated(gbsa)) then - A(:n, :n) = A(:n, :n) + gbsa%bornMat(:, :) - end if + if (allocated(gbsa)) then + A(:n, :n) = A(:n, :n) + gbsa%bornMat(:, :) + end if ! call prmat(6,A,m,m,'A eg') - allocate(ipiv(m)) - - if(single) then - allocate(A4(m,m),x4(m)) - A4=A - x4=x - deallocate(A,x) - call mctc_sytrf(env, a4, ipiv) - call mctc_sytrs(env, a4, x4, ipiv) - q(1:n)=x4(1:n) - deallocate(A4,x4) - else - call mctc_sytrf(env, a, ipiv) - call mctc_sytrs(env, a, x, ipiv) - q(1:n)=x(1:n) - deallocate(A,x) - endif + allocate(ipiv(m)) - call env%check(exitRun) - if(exitRun) then - call env%error('Solving linear equations failed', source) - return - end if + if(single) then + + allocate(A4(m,m),x4(m)) + A4=A + x4=x + deallocate(A,x) + call mctc_sytrf(env, a4, ipiv) + call mctc_sytrs(env, a4, x4, ipiv) + q(1:n)=x4(1:n) + deallocate(A4,x4) + + else + + call mctc_sytrf(env, a, ipiv) + call mctc_sytrs(env, a, x, ipiv) + q(1:n)=x(1:n) + deallocate(A,x) + + endif - if(n.eq.1) q(1)=chrg + call env%check(exitRun) + + if(exitRun) then + call env%error('Solving linear equations failed', source) + return + end if -! energy - es = 0.0_wp - do i=1,n + if(n.eq.1) q(1)=chrg + + ! energy ! + + es = 0.0_wp + do i=1,n + ii = i*(i-1)/2 - do j=1,i-1 + + do j=1,i-1 ij = ii+j tmp =eeqtmp(2,ij) es = es + q(i)*q(j)*tmp/r(ij) enddo + es = es - q(i)*(topo%chieeq(i) + param%cnf(at(i))*sqrt(cn(i))) & - & + q(i)*q(i)*0.5d0*(topo%gameeq(i)+tsqrt2pi/sqrt(topo%alpeeq(i))) - enddo + & + q(i)*q(i)*0.5d0*(topo%gameeq(i)+tsqrt2pi/sqrt(topo%alpeeq(i))) + + enddo - !work = x - !call dsymv('u', n, 0.5d0, A, m, q, 1, -1.0_wp, work, 1) - !es = ddot(n, q, 1, work, 1) + !work = x + !call dsymv('u', n, 0.5d0, A, m, q, 1, -1.0_wp, work, 1) + !es = ddot(n, q, 1, work, 1) ! deallocate(cn) - end subroutine goed_gfnff +end subroutine goed_gfnff !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ! HB energy and analytical gradient !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc -!subroutine for case 1: A...H...B +!> Case 1: A...H...B subroutine abhgfnff_eg1(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,n,at(n) - real*8 xyz(3,n),energy,gdr(3,3) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp,dd24a,dd24b - real*8 ratio1,ratio2,ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 drah(3),drbh(3),drab(3),drm(3) - real*8 dg(3),dga(3),dgb(3),dgh(3) - real*8 ga(3),gb(3),gh(3) - real*8 gi,denom,ratio,tmp,qhoutl,radab,rahprbh - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo - real*8 bas,aci - real*8 eabh - real*8 aterm,rterm,dterm,sterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 caa,cbb - real*8 shortcut - - integer i,j,ij,lina - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - gdr = 0 - energy=0 - - call hbonds(A,B,ca,cb,param,topo) - -! A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - -! A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - -! B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**param%hbalp - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - rdamp = damp/rab2/rab - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - -! donor-acceptor term - rah4 = rah2*rah2 - rbh4 = rbh2*rbh2 - denom = 1.d0/(rah4+rbh4) - - caa=qa*ca(1) - cbb=qb*cb(1) - qhoutl=qh*outl - - bas = (caa*rah4 + cbb*rbh4)*denom - aci = (cb(2)*rah4+ca(2)*rbh4)*denom - -! energy - rterm = -aci*rdamp*qhoutl - energy = bas*rterm - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - - aterm= -aci*bas*rdamp*qh - sterm= -rdamp*bas*qhoutl - dterm= -aci*bas*qhoutl - - tmp=denom*denom*4.0d0 - dd24a=rah2*rbh4*tmp - dd24b=rbh2*rah4*tmp - -! donor-acceptor part: bas - gi = (caa-cbb)*dd24a*rterm - ga(1:3) = gi*drah(1:3) - gi = (cbb-caa)*dd24b*rterm - gb(1:3) = gi*drbh(1:3) - gh(1:3) = -ga(1:3)-gb(1:3) - -! donor-acceptor part: aci - gi = (cb(2)-ca(2))*dd24a - dga(1:3) = gi*drah(1:3)*sterm - ga(1:3) = ga(1:3) + dga(1:3) - - gi = (ca(2)-cb(2))*dd24b - dgb(1:3) = gi*drbh(1:3)*sterm - gb(1:3) = gb(1:3) + dgb(1:3) - - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -! damping part rab - gi = rdamp*(-(2.d0*param%hbalp*ratio1/(1+ratio1))+(2.d0*param%hbalp*ratio3/(1+ratio3))-3.d0)/rab2 - dg(1:3) = gi*drab(1:3)*dterm - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rab - gi = aterm*2.d0*ratio2*expo*rahprbh/(1+ratio2)**2/(rahprbh-rab)/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - tmp= -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - dga(1:3) = drah(1:3)*tmp/rah - ga(1:3) = ga(1:3) + dga(1:3) - dgb(1:3) = drbh(1:3)*tmp/rbh - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -! move gradients into place - gdr(1:3,1) = ga(1:3) - gdr(1:3,2) = gb(1:3) - gdr(1:3,3) = gh(1:3) + + implicit none + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer A,B,H,n,at(n) + real*8 xyz(3,n),energy,gdr(3,3) + real*8 q(n) + + !> squared dist + real*8 sqrab(n*(n+1)/2) + + !> distance + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp,dd24a,dd24b + real*8 ratio1,ratio2,ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 drah(3),drbh(3),drab(3),drm(3) + real*8 dg(3),dga(3),dgb(3),dgh(3) + real*8 ga(3),gb(3),gh(3) + real*8 gi,denom,ratio,tmp,qhoutl,radab,rahprbh + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo + real*8 bas,aci + real*8 eabh + real*8 aterm,rterm,dterm,sterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 caa,cbb + real*8 shortcut + integer i,j,ij,lina + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + gdr = 0 + energy=0 + + call hbonds(A,B,ca,cb,param,topo) + + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**param%hbalp + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + rdamp = damp/rab2/rab + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + ! donor-acceptor term ! + rah4 = rah2*rah2 + rbh4 = rbh2*rbh2 + denom = 1.d0/(rah4+rbh4) + + caa=qa*ca(1) + cbb=qb*cb(1) + qhoutl=qh*outl + + bas = (caa*rah4 + cbb*rbh4)*denom + aci = (cb(2)*rah4+ca(2)*rbh4)*denom + + ! energy ! + rterm = -aci*rdamp*qhoutl + energy = bas*rterm + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + + aterm= -aci*bas*rdamp*qh + sterm= -rdamp*bas*qhoutl + dterm= -aci*bas*qhoutl + + tmp=denom*denom*4.0d0 + dd24a=rah2*rbh4*tmp + dd24b=rbh2*rah4*tmp + + ! donor-acceptor part: bas ! + gi = (caa-cbb)*dd24a*rterm + ga(1:3) = gi*drah(1:3) + gi = (cbb-caa)*dd24b*rterm + gb(1:3) = gi*drbh(1:3) + gh(1:3) = -ga(1:3)-gb(1:3) + + ! donor-acceptor part: aci ! + gi = (cb(2)-ca(2))*dd24a + dga(1:3) = gi*drah(1:3)*sterm + ga(1:3) = ga(1:3) + dga(1:3) + + gi = (ca(2)-cb(2))*dd24b + dgb(1:3) = gi*drbh(1:3)*sterm + gb(1:3) = gb(1:3) + dgb(1:3) + + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + ! damping part rab ! + gi = rdamp*(-(2.d0*param%hbalp*ratio1/(1+ratio1))+(2.d0*param%hbalp*ratio3/(1+ratio3))-3.d0)/rab2 + dg(1:3) = gi*drab(1:3)*dterm + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rab ! + gi = aterm*2.d0*ratio2*expo*rahprbh/(1+ratio2)**2/(rahprbh-rab)/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + tmp= -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + dga(1:3) = drah(1:3)*tmp/rah + ga(1:3) = ga(1:3) + dga(1:3) + dgb(1:3) = drbh(1:3)*tmp/rbh + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + ! move gradients into place ! + gdr(1:3,1) = ga(1:3) + gdr(1:3,2) = gb(1:3) + gdr(1:3,3) = gh(1:3) end subroutine abhgfnff_eg1 -!subroutine for case 2: A-H...B including orientation of neighbors at B +!> Case 2: A-H...B including orientation of neighbors at B subroutine abhgfnff_eg2new(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,n,at(n) - real*8 xyz(3,n),energy,gdr(3,n) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp - real*8 ddamp,rabdamp,rbhdamp - real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) - real*8 drah(3),drbh(3),drab(3),drm(3) - real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) - real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) - real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) - real*8 denom,ratio,qhoutl,radab - real*8 gi,gi_nb(topo%nb(20,B)) - real*8 tmp1,tmp2(topo%nb(20,B)) - real*8 rahprbh,ranbprbnb(topo%nb(20,B)) - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) - real*8 eabh - real*8 aterm,dterm,nbterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 shortcut - real*8 const - real*8 outl_nb(topo%nb(20,B)),outl_nb_tot - real*8 hbnbcut_save - logical mask_nb(topo%nb(20,B)) - -! proportion between Rbh und Rab distance dependencies - real*8 :: p_bh - real*8 :: p_ab - - integer i,j,ij,lina,nbb - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - p_bh=1.d0+param%hbabmix - p_ab= -param%hbabmix - - gdr = 0 - energy = 0 - - call hbonds(A,B,ca,cb,param,topo) - - nbb=topo%nb(20,B) -! Neighbours of B - do i=1,nbb -! compute distances - dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) - drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) -! A-nb(B) distance - ranb2(i) = sum(dranb(1:3,i)**2) - ranb(i) = sqrt(ranb2(i)) -! B-nb(B) distance - rbnb2(i) = sum(drbnb(1:3,i)**2) - rbnb(i) = sqrt(rbnb2(i)) - end do - -! A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - -! A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - -! B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp: A-H...B - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! out-of-line damp: A...nb(B)-B - if(at(B).eq.7.and.topo%nb(20,B).eq.1) then - hbnbcut_save = 2.0 - else - hbnbcut_save = param%hbnbcut - end if - do i=1,nbb - ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 - expo_nb(i)=(hbnbcut_save/radab)*(ranbprbnb(i)/rab-1.d0) - ratio2_nb(i)=exp(-expo_nb(i))**(1.0) - outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 - end do - outl_nb_tot = product(outl_nb) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**param%hbalp - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) - rbhdamp = damp * ( (p_bh/rbh2/rbh) ) - rabdamp = damp * ( (p_ab/rab2/rab) ) - rdamp = rbhdamp + rabdamp - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - - qhoutl=qh*outl*outl_nb_tot - -! constant values, no gradient - const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh - -! energy - energy = -rdamp*qhoutl*const - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - - aterm = -rdamp*qh*outl_nb_tot*const - nbterm = -rdamp*qh*outl*const - dterm = -qhoutl*const - -!------------------------------------------------------------------------------ -! damping part: rab - gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 - gi = gi*dterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = dg(1:3) - gb(1:3) = -dg(1:3) - -!------------------------------------------------------------------------------ -! damping part: rbh - gi = -3.d0*rbhdamp/rbh2 - gi = gi*dterm - dg(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3)+dg(1:3) - gh(1:3) = - dg(1:3) - -!------------------------------------------------------------------------------ -! angular A-H...B term -!------------------------------------------------------------------------------ -! out of line term: rab - tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - gi = -tmp1 *rahprbh/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - gi = tmp1/rah - dga(1:3) = gi*drah(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp1/rbh - dgb(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -!------------------------------------------------------------------------------ -! angular A...nb(B)-B term -!------------------------------------------------------------------------------ -! out of line term: rab + + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer A,B,H,n,at(n) + real*8 xyz(3,n),energy,gdr(3,n) + real*8 q(n) + + !> squared dist + real*8 sqrab(n*(n+1)/2) + + !> dist + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ddamp,rabdamp,rbhdamp + real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) + real*8 drah(3),drbh(3),drab(3),drm(3) + real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) + real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) + real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) + real*8 denom,ratio,qhoutl,radab + real*8 gi,gi_nb(topo%nb(20,B)) + real*8 tmp1,tmp2(topo%nb(20,B)) + real*8 rahprbh,ranbprbnb(topo%nb(20,B)) + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) + real*8 eabh + real*8 aterm,dterm,nbterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 shortcut + real*8 const + real*8 outl_nb(topo%nb(20,B)),outl_nb_tot + real*8 hbnbcut_save + logical mask_nb(topo%nb(20,B)) + + !> proportion between Rbh und Rab distance dependencies + real*8 :: p_bh + real*8 :: p_ab + integer i,j,ij,lina,nbb + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + p_bh=1.d0+param%hbabmix + p_ab= -param%hbabmix + + gdr = 0 + energy = 0 + + call hbonds(A,B,ca,cb,param,topo) + + nbb=topo%nb(20,B) + ! Neighbours of B ! + do i=1,nbb + ! compute distances ! + dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) + drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) + ! A-nb(B) distance ! + ranb2(i) = sum(dranb(1:3,i)**2) + ranb(i) = sqrt(ranb2(i)) + ! B-nb(B) distance ! + rbnb2(i) = sum(drbnb(1:3,i)**2) + rbnb(i) = sqrt(rbnb2(i)) + end do + + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp: A-H...B ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! out-of-line damp: A...nb(B)-B ! + if(at(B).eq.7.and.topo%nb(20,B).eq.1) then + hbnbcut_save = 2.0 + else + hbnbcut_save = param%hbnbcut + end if + do i=1,nbb + ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 + expo_nb(i)=(hbnbcut_save/radab)*(ranbprbnb(i)/rab-1.d0) + ratio2_nb(i)=exp(-expo_nb(i))**(1.0) + outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 + end do + outl_nb_tot = product(outl_nb) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**param%hbalp + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) + rbhdamp = damp * ( (p_bh/rbh2/rbh) ) + rabdamp = damp * ( (p_ab/rab2/rab) ) + rdamp = rbhdamp + rabdamp + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + qhoutl=qh*outl*outl_nb_tot + + ! constant values, no gradient ! + const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh + + ! energy ! + energy = -rdamp*qhoutl*const + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + + aterm = -rdamp*qh*outl_nb_tot*const + nbterm = -rdamp*qh*outl*const + dterm = -qhoutl*const + + ! damping part: rab ! + gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 + gi = gi*dterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = dg(1:3) + gb(1:3) = -dg(1:3) + + ! damping part: rbh ! + gi = -3.d0*rbhdamp/rbh2 + gi = gi*dterm + dg(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3)+dg(1:3) + gh(1:3) = - dg(1:3) + + !-----------------------! + ! angular A-H...B term ! + !-----------------------! + + ! out of line term: rab ! + tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + gi = -tmp1 *rahprbh/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + gi = tmp1/rah + dga(1:3) = gi*drah(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp1/rbh + dgb(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + !--------------------------! + ! angular A...nb(B)-B term ! + !--------------------------! + + ! out of line term: rab ! + mask_nb=.true. + do i=1,nbb + mask_nb(i)=.false. + tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& + & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) + gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 + dg(1:3) = gi_nb(i)*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) mask_nb=.true. - do i=1,nbb - mask_nb(i)=.false. - tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& - & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) - gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 - dg(1:3) = gi_nb(i)*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - mask_nb=.true. - end do - -! out of line term: ranb,rbnb - do i=1,nbb - gi_nb(i) = tmp2(i)/ranb(i) - dga(1:3) = gi_nb(i)*dranb(1:3,i) - ga(1:3) = ga(1:3) + dga(1:3) - gi_nb(i) = tmp2(i)/rbnb(i) - dgb(1:3) = gi_nb(i)*drbnb(1:3,i) - gb(1:3) = gb(1:3) + dgb(1:3) - dgnb(1:3) = -dga(1:3)-dgb(1:3) - gnb(1:3,i) = dgnb(1:3) - end do - -!------------------------------------------------------------------------------ - if(nbb.lt.1) then - gdr(1:3,A) = gdr(1:3,A) + ga(1:3) - gdr(1:3,B) = gdr(1:3,B) + gb(1:3) - gdr(1:3,H) = gdr(1:3,H) + gh(1:3) - return - endif - -!------------------------------------------------------------------------------ -! move gradients into place + end do + + ! out of line term: ranb,rbnb ! + do i=1,nbb + gi_nb(i) = tmp2(i)/ranb(i) + dga(1:3) = gi_nb(i)*dranb(1:3,i) + ga(1:3) = ga(1:3) + dga(1:3) + gi_nb(i) = tmp2(i)/rbnb(i) + dgb(1:3) = gi_nb(i)*drbnb(1:3,i) + gb(1:3) = gb(1:3) + dgb(1:3) + dgnb(1:3) = -dga(1:3)-dgb(1:3) + gnb(1:3,i) = dgnb(1:3) + end do + + if(nbb.lt.1) then gdr(1:3,A) = gdr(1:3,A) + ga(1:3) gdr(1:3,B) = gdr(1:3,B) + gb(1:3) gdr(1:3,H) = gdr(1:3,H) + gh(1:3) - do i=1,nbb - gdr(1:3,topo%nb(i,B)) = gdr(1:3,topo%nb(i,B)) + gnb(1:3,i) - end do + return + endif + + !---------------------------! + + ! move gradients into place ! + gdr(1:3,A) = gdr(1:3,A) + ga(1:3) + gdr(1:3,B) = gdr(1:3,B) + gb(1:3) + gdr(1:3,H) = gdr(1:3,H) + gh(1:3) + do i=1,nbb + gdr(1:3,topo%nb(i,B)) = gdr(1:3,topo%nb(i,B)) + gnb(1:3,i) + end do end subroutine abhgfnff_eg2new -!subroutine for case 2: A-H...B including LP position +!> Case 2: A-H...B including LP position subroutine abhgfnff_eg2_rnr(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,n,at(n) - real*8 xyz(3,n),energy,gdr(3,n) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp - real*8 ddamp,rabdamp,rbhdamp - real*8 ratio1,ratio2,ratio2_lp,ratio2_nb(topo%nb(20,B)),ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) - real*8 drah(3),drbh(3),drab(3),drm(3),dralp(3),drblp(3) - real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) - real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) - real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)),gnb_lp(3),glp(3) - real*8 denom,ratio,qhoutl,radab - real*8 gi,gi_nb(topo%nb(20,B)) - real*8 tmp1,tmp2(topo%nb(20,B)),tmp3 - real*8 rahprbh,ranbprbnb(topo%nb(20,B)) - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_lp,expo_nb(topo%nb(20,B)) - real*8 eabh - real*8 aterm,dterm,nbterm,lpterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 shortcut - real*8 const - real*8 outl_nb(topo%nb(20,B)),outl_nb_tot,outl_lp - real*8 vector(3),vnorm - real*8 gii(3,3) - real*8 unit_vec(3) - real*8 drnb(3,topo%nb(20,B)) - real*8 lp(3) !lonepair position - real*8 lp_dist !distance parameter between B and lonepair - real*8 ralp,ralp2,rblp,rblp2,ralpprblp - logical mask_nb(topo%nb(20,B)) - -! proportion between Rbh und Rab distance dependencies - real*8 :: p_bh - real*8 :: p_ab -! lone-pair out-of-line damping - real*8 hblpcut - - integer i,j,ij,lina,nbb - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - p_bh=1.d0+param%hbabmix - p_ab= -param%hbabmix - - gdr = 0 - energy = 0 - vector = 0 - lp_dist = 0.50-0.018*param%repz(at(B)) - hblpcut=56 - - call hbonds(A,B,ca,cb,param,topo) - - nbb=topo%nb(20,B) -! Neighbours of B - do i=1,nbb -! compute distances - dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) - drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) -! A-nb(B) distance - ranb2(i) = sum(dranb(1:3,i)**2) - ranb(i) = sqrt(ranb2(i)) -! B-nb(B) distance - rbnb2(i) = sum(drbnb(1:3,i)**2) - rbnb(i) = sqrt(rbnb2(i)) - end do + + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer A,B,H,n,at(n) + real*8 xyz(3,n),energy,gdr(3,n) + real*8 q(n) + + !> squared dist + real*8 sqrab(n*(n+1)/2) + + !> distance + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ddamp,rabdamp,rbhdamp + real*8 ratio1,ratio2,ratio2_lp,ratio2_nb(topo%nb(20,B)),ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) + real*8 drah(3),drbh(3),drab(3),drm(3),dralp(3),drblp(3) + real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) + real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) + real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)),gnb_lp(3),glp(3) + real*8 denom,ratio,qhoutl,radab + real*8 gi,gi_nb(topo%nb(20,B)) + real*8 tmp1,tmp2(topo%nb(20,B)),tmp3 + real*8 rahprbh,ranbprbnb(topo%nb(20,B)) + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_lp,expo_nb(topo%nb(20,B)) + real*8 eabh + real*8 aterm,dterm,nbterm,lpterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 shortcut + real*8 const + real*8 outl_nb(topo%nb(20,B)),outl_nb_tot,outl_lp + real*8 vector(3),vnorm + real*8 gii(3,3) + real*8 unit_vec(3) + real*8 drnb(3,topo%nb(20,B)) + real*8 lp(3) !lonepair position + real*8 lp_dist !distance parameter between B and lonepair + real*8 ralp,ralp2,rblp,rblp2,ralpprblp + logical mask_nb(topo%nb(20,B)) + + !> proportion between Rbh und Rab distance dependencies + real*8 :: p_bh + real*8 :: p_ab + + !>lone-pair out-of-line damping + real*8 hblpcut + integer i,j,ij,lina,nbb + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + p_bh=1.d0+param%hbabmix + p_ab= -param%hbabmix + + gdr = 0 + energy = 0 + vector = 0 + lp_dist = 0.50-0.018*param%repz(at(B)) + hblpcut=56 + + call hbonds(A,B,ca,cb,param,topo) + + nbb=topo%nb(20,B) + + ! Neighbours of B ! + do i=1,nbb + ! compute distances ! + dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) + drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) + + ! A-nb(B) distance ! + ranb2(i) = sum(dranb(1:3,i)**2) + ranb(i) = sqrt(ranb2(i)) + + ! B-nb(B) distance ! + rbnb2(i) = sum(drbnb(1:3,i)**2) + rbnb(i) = sqrt(rbnb2(i)) + end do -! Neighbours of B - do i=1,nbb - drnb(1:3,i)=xyz(1:3,topo%nb(i,B))-xyz(1:3,B) - vector = vector + drnb(1:3,i) - end do + ! Neighbours of B ! + do i=1,nbb + drnb(1:3,i)=xyz(1:3,topo%nb(i,B))-xyz(1:3,B) + vector = vector + drnb(1:3,i) + end do - vnorm = norm2(vector) -! lonepair coordinates - if(vnorm.gt.1.d-10) then + vnorm = norm2(vector) + + ! lonepair coordinates ! + if(vnorm.gt.1.d-10) then lp = xyz(1:3,B) - lp_dist * ( vector / vnorm ) - else + else lp = xyz(1:3,B) nbb = 0 - endif + endif -! A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - -! A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - -! B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp: A-H...B - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! out-of-line damp: A...LP-B - rblp2 = sum( ( xyz(1:3,B) - lp(1:3) )**2 ) - rblp = sqrt(rblp2) - ralp2 = sum( ( xyz(1:3,A) - lp(1:3) )**2 ) - ralp = sqrt(ralp2) - ralpprblp=ralp+rblp+1.d-12 - expo_lp=(hblpcut/radab)*(ralpprblp/rab-1.d0) - ratio2_lp=exp(expo_lp) - outl_lp=2.d0/(1.d0+ratio2_lp) - -! out-of-line damp: A...nb(B)-B - do i=1,nbb - ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 - expo_nb(i)=(param%hbnbcut/radab)*(ranbprbnb(i)/rab-1.d0) - ratio2_nb(i)=exp(-expo_nb(i))**(1.0) - outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 - end do - outl_nb_tot = product(outl_nb) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**param%hbalp - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) - rbhdamp = damp * ( (p_bh/rbh2/rbh) ) - rabdamp = damp * ( (p_ab/rab2/rab) ) - rdamp = rbhdamp + rabdamp - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - - qhoutl=qh*outl*outl_nb_tot*outl_lp - -! constant values, no gradient - const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh - -! energy - energy = -rdamp*qhoutl*const - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - dralp(1:3)=xyz(1:3,A)-lp(1:3) - drblp(1:3)=xyz(1:3,B)-lp(1:3) - - aterm = -rdamp*qh*outl_nb_tot*outl_lp*const - nbterm = -rdamp*qh*outl*outl_lp*const - lpterm = -rdamp*qh*outl*outl_nb_tot*const - dterm = -qhoutl*const - -!------------------------------------------------------------------------------ -! damping part: rab - gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 - gi = gi*dterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = dg(1:3) - gb(1:3) = -dg(1:3) - -!------------------------------------------------------------------------------ -! damping part: rbh - gi = -3.d0*rbhdamp/rbh2 - gi = gi*dterm - dg(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3)+dg(1:3) - gh(1:3) = - dg(1:3) - -!------------------------------------------------------------------------------ -! angular A-H...B term -!------------------------------------------------------------------------------ -! out of line term: rab - tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - gi = -tmp1 *rahprbh/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - gi = tmp1/rah - dga(1:3) = gi*drah(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp1/rbh - dgb(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -!!------------------------------------------------------------------------------ -!! angular A...LP-B term -!!------------------------------------------------------------------------------ -! out of line term: rab - tmp3 = -2.d0*lpterm*ratio2_lp*expo_lp/(1+ratio2_lp)**2/(ralpprblp-rab) - gi = -tmp3 *ralpprblp/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: ralp,rblp - gi = tmp3/ralp - dga(1:3) = gi*dralp(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp3/(rblp+1.0d-12) - dgb(1:3) = gi*drblp(1:3) - gb(1:3) = gb(1:3) - dga(1:3) - glp(1:3) = -dga(1:3)!-dgb(1:3) - -! neighbor part: LP + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp: A-H...B ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! out-of-line damp: A...LP-B ! + rblp2 = sum( ( xyz(1:3,B) - lp(1:3) )**2 ) + rblp = sqrt(rblp2) + ralp2 = sum( ( xyz(1:3,A) - lp(1:3) )**2 ) + ralp = sqrt(ralp2) + ralpprblp=ralp+rblp+1.d-12 + expo_lp=(hblpcut/radab)*(ralpprblp/rab-1.d0) + ratio2_lp=exp(expo_lp) + outl_lp=2.d0/(1.d0+ratio2_lp) + + ! out-of-line damp: A...nb(B)-B ! + do i=1,nbb + ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 + expo_nb(i)=(param%hbnbcut/radab)*(ranbprbnb(i)/rab-1.d0) + ratio2_nb(i)=exp(-expo_nb(i))**(1.0) + outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 + end do + outl_nb_tot = product(outl_nb) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**param%hbalp + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) + rbhdamp = damp * ( (p_bh/rbh2/rbh) ) + rabdamp = damp * ( (p_ab/rab2/rab) ) + rdamp = rbhdamp + rabdamp + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + qhoutl=qh*outl*outl_nb_tot*outl_lp + + ! constant values, no gradient ! + const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh + + ! energy ! + energy = -rdamp*qhoutl*const + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + dralp(1:3)=xyz(1:3,A)-lp(1:3) + drblp(1:3)=xyz(1:3,B)-lp(1:3) + + aterm = -rdamp*qh*outl_nb_tot*outl_lp*const + nbterm = -rdamp*qh*outl*outl_lp*const + lpterm = -rdamp*qh*outl*outl_nb_tot*const + dterm = -qhoutl*const + + ! damping part: rab ! + gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 + gi = gi*dterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = dg(1:3) + gb(1:3) = -dg(1:3) + + ! damping part: rbh ! + gi = -3.d0*rbhdamp/rbh2 + gi = gi*dterm + dg(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3)+dg(1:3) + gh(1:3) = - dg(1:3) + + !----------------------! + ! angular A-H...B term ! + !----------------------! + + ! out of line term: rab ! + tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + gi = -tmp1 *rahprbh/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + gi = tmp1/rah + dga(1:3) = gi*drah(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp1/rbh + dgb(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + !-----------------------! + ! angular A...LP-B term ! + !-----------------------! + + ! out of line term: rab ! + tmp3 = -2.d0*lpterm*ratio2_lp*expo_lp/(1+ratio2_lp)**2/(ralpprblp-rab) + gi = -tmp3 *ralpprblp/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: ralp,rblp ! + gi = tmp3/ralp + dga(1:3) = gi*dralp(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp3/(rblp+1.0d-12) + dgb(1:3) = gi*drblp(1:3) + gb(1:3) = gb(1:3) - dga(1:3) + glp(1:3) = -dga(1:3)!-dgb(1:3) + + ! neighbor part: LP ! + unit_vec=0 + do i=1,3 + unit_vec(i)=-1 + gii(1:3,i) = -lp_dist * dble(nbb) * ( unit_vec/vnorm + (vector*vector(i)/sum(vector**2)**(1.5d0)) ) unit_vec=0 - do i=1,3 - unit_vec(i)=-1 - gii(1:3,i) = -lp_dist * dble(nbb) * ( unit_vec/vnorm + (vector*vector(i)/sum(vector**2)**(1.5d0)) ) - unit_vec=0 - end do - gnb_lp=matmul(gii,glp) - -!------------------------------------------------------------------------------ -! angular A...nb(B)-B term -!------------------------------------------------------------------------------ -! out of line term: rab + end do + gnb_lp=matmul(gii,glp) + + !--------------------------! + ! angular A...nb(B)-B term ! + !--------------------------! + + ! out of line term: rab ! + mask_nb=.true. + do i=1,nbb + mask_nb(i)=.false. + tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& + & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) + gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 + dg(1:3) = gi_nb(i)*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) mask_nb=.true. - do i=1,nbb - mask_nb(i)=.false. - tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& - & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) - gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 - dg(1:3) = gi_nb(i)*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - mask_nb=.true. - end do - -! out of line term: ranb,rbnb - do i=1,nbb - gi_nb(i) = tmp2(i)/ranb(i) - dga(1:3) = gi_nb(i)*dranb(1:3,i) - ga(1:3) = ga(1:3) + dga(1:3) - gi_nb(i) = tmp2(i)/rbnb(i) - dgb(1:3) = gi_nb(i)*drbnb(1:3,i) - gb(1:3) = gb(1:3) + dgb(1:3) - dgnb(1:3) = -dga(1:3)-dgb(1:3) - gnb(1:3,i) = dgnb(1:3) - end do - -!------------------------------------------------------------------------------ - if(nbb.lt.1) then - gdr(1:3,A) = gdr(1:3,A) + ga(1:3) - gdr(1:3,B) = gdr(1:3,B) + gb(1:3) - gdr(1:3,H) = gdr(1:3,H) + gh(1:3) - return - endif - -!------------------------------------------------------------------------------ -! move gradients into place + end do + + ! out of line term: ranb,rbnb ! + do i=1,nbb + gi_nb(i) = tmp2(i)/ranb(i) + dga(1:3) = gi_nb(i)*dranb(1:3,i) + ga(1:3) = ga(1:3) + dga(1:3) + gi_nb(i) = tmp2(i)/rbnb(i) + dgb(1:3) = gi_nb(i)*drbnb(1:3,i) + gb(1:3) = gb(1:3) + dgb(1:3) + dgnb(1:3) = -dga(1:3)-dgb(1:3) + gnb(1:3,i) = dgnb(1:3) + end do + + if(nbb.lt.1) then gdr(1:3,A) = gdr(1:3,A) + ga(1:3) - gdr(1:3,B) = gdr(1:3,B) + gb(1:3) + gnb_lp(1:3) + gdr(1:3,B) = gdr(1:3,B) + gb(1:3) gdr(1:3,H) = gdr(1:3,H) + gh(1:3) - do i=1,nbb - gdr(1:3,topo%nb(i,B)) = gdr(1:3,topo%nb(i,B)) + gnb(1:3,i) - gnb_lp(1:3)/dble(nbb) - end do + return + endif + + ! move gradients into place ! + gdr(1:3,A) = gdr(1:3,A) + ga(1:3) + gdr(1:3,B) = gdr(1:3,B) + gb(1:3) + gnb_lp(1:3) + gdr(1:3,H) = gdr(1:3,H) + gh(1:3) + do i=1,nbb + gdr(1:3,topo%nb(i,B)) = gdr(1:3,topo%nb(i,B)) + gnb(1:3,i) - gnb_lp(1:3)/dble(nbb) + end do end subroutine abhgfnff_eg2_rnr -!subroutine for case 3: A-H...B, B is 0=C including two in plane LPs at B -!this is the multiplicative version of incorporationg etors and ebend -!equal to abhgfnff_eg2_new multiplied by etors and eangl +!> case 3: A-H...B, B is 0=C including two in plane LPs at B +!> this is the multiplicative version of incorporationg etors and ebend +!> equal to abhgfnff_eg2_new multiplied by etors and eangl subroutine abhgfnff_eg3(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - use xtb_mctc_constants - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,n,at(n) - real*8 xyz(3,n),energy,gdr(3,n) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp - real*8 ddamp,rabdamp,rbhdamp - real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) - real*8 drah(3),drbh(3),drab(3),drm(3) - real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) - real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) - real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) - real*8 phi,phi0,r0,t0,fc,tshift,bshift - real*8 eangl,etors,gangl(3,n),gtors(3,n) - real*8 etmp(20),g3tmp(3,3),g4tmp(3,4,20) - real*8 ratio,qhoutl,radab - real*8 gi,gi_nb(topo%nb(20,B)) - real*8 tmp1,tmp2(topo%nb(20,B)) - real*8 rahprbh,ranbprbnb(topo%nb(20,B)) - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) - real*8 eabh - real*8 aterm,dterm,nbterm,bterm,tterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 shortcut - real*8 tlist(5,topo%nb(20,topo%nb(1,B))) - real*8 vtors(2,topo%nb(20,topo%nb(1,B))) - real*8 valijklff - real*8 const - real*8 outl_nb(topo%nb(20,B)),outl_nb_tot - logical mask_nb(topo%nb(20,B)),t_mask(20) - -! proportion between Rbh und Rab distance dependencies - real*8 :: p_bh - real*8 :: p_ab - - integer C,D - integer i,j,ii,jj,kk,ll,ij,lina - integer nbb,nbc - integer ntors,rn - - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - p_bh=1.d0+param%hbabmix - p_ab= -param%hbabmix - - gdr = 0 - energy = 0 - etors = 0 - gtors = 0 - eangl = 0 - gangl = 0 - - call hbonds(A,B,ca,cb,param,topo) - - !Determine all neighbors for torsion term - ! A - ! \ tors: - ! H ll - ! : \ - ! O jj - ! || | - ! C kk - ! / \ \ - ! R1 R2 ii - !------------------------------------------ - nbb=topo%nb(20,B) - C=topo%nb(nbb,B) - nbc=topo%nb(20,C) - ntors=nbc-nbb - - nbb=topo%nb(20,B) -! Neighbours of B - do i=1,nbb -! compute distances - dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) - drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) -! A-nb(B) distance - ranb2(i) = sum(dranb(1:3,i)**2) - ranb(i) = sqrt(ranb2(i)) -! B-nb(B) distance - rbnb2(i) = sum(drbnb(1:3,i)**2) - rbnb(i) = sqrt(rbnb2(i)) - end do - -! A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - -! A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - -! B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp: A-H...B - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! out-of-line damp: A...nb(B)-B - do i=1,nbb - ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 - expo_nb(i)=(param%hbnbcut/radab)*(ranbprbnb(i)/rab-1.d0) - ratio2_nb(i)=exp(-expo_nb(i)) - outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 - end do - outl_nb_tot = product(outl_nb) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**6 - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) - rbhdamp = damp * ( (p_bh/rbh2/rbh) ) - rabdamp = damp * ( (p_ab/rab2/rab) ) - rdamp = rbhdamp + rabdamp - - !Set up torsion paramter - j = 0 - do i = 1,nbc - if( topo%nb(i,C) == B ) cycle - j = j + 1 - tlist(1,j)=topo%nb(i,C) - tlist(2,j)=B - tlist(3,j)=C - tlist(4,j)=H - tlist(5,j)=2 - t0=180 - phi0=t0*pi/180. - vtors(1,j)=phi0-(pi/2.0) - vtors(2,j)=param%tors_hb - end do - - !Calculate etors - do i = 1,ntors - ii =tlist(1,i) - jj =tlist(2,i) - kk =tlist(3,i) - ll =tlist(4,i) - rn =tlist(5,i) - phi0=vtors(1,i) - tshift=vtors(2,i) - phi=valijklff(n,xyz,ii,jj,kk,ll) - call egtors_nci_mul(ii,jj,kk,ll,rn,phi0,tshift,n,at,xyz,etmp(i),g4tmp(:,:,i)) - end do - etors=product(etmp(1:ntors)) - !Calculate gtors + + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer A,B,H,n,at(n) + real*8 xyz(3,n),energy,gdr(3,n) + real*8 q(n) + + !> squared dist + real*8 sqrab(n*(n+1)/2) + + !> dist + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ddamp,rabdamp,rbhdamp + real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) + real*8 drah(3),drbh(3),drab(3),drm(3) + real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) + real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) + real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) + real*8 phi,phi0,r0,t0,fc,tshift,bshift + real*8 eangl,etors,gangl(3,n),gtors(3,n) + real*8 etmp(20),g3tmp(3,3),g4tmp(3,4,20) + real*8 ratio,qhoutl,radab + real*8 gi,gi_nb(topo%nb(20,B)) + real*8 tmp1,tmp2(topo%nb(20,B)) + real*8 rahprbh,ranbprbnb(topo%nb(20,B)) + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) + real*8 eabh + real*8 aterm,dterm,nbterm,bterm,tterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 shortcut + real*8 tlist(5,topo%nb(20,topo%nb(1,B))) + real*8 vtors(2,topo%nb(20,topo%nb(1,B))) + real*8 valijklff + real*8 const + real*8 outl_nb(topo%nb(20,B)),outl_nb_tot + logical mask_nb(topo%nb(20,B)),t_mask(20) + + !> proportion between Rbh und Rab distance dependencies + real*8 :: p_bh + real*8 :: p_ab + + integer C,D + integer i,j,ii,jj,kk,ll,ij,lina + integer nbb,nbc + integer ntors,rn + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + p_bh=1.d0+param%hbabmix + p_ab= -param%hbabmix + + gdr = 0 + energy = 0 + etors = 0 + gtors = 0 + eangl = 0 + gangl = 0 + + call hbonds(A,B,ca,cb,param,topo) + + ! Determine all neighbors for torsion term ! + ! A ! + ! \ tors: ! + ! H ll ! + ! : \ ! + ! O jj ! + ! || | ! + ! C kk ! + ! / \ \ ! + ! R1 R2 ii ! + ! -----------------------------------------! + + nbb=topo%nb(20,B) + C=topo%nb(nbb,B) + nbc=topo%nb(20,C) + ntors=nbc-nbb + + nbb=topo%nb(20,B) + + ! Neighbours of B ! + do i=1,nbb + ! compute distances ! + dranb(1:3,i) = xyz(1:3,A) - xyz(1:3,topo%nb(i,B)) + drbnb(1:3,i) = xyz(1:3,B) - xyz(1:3,topo%nb(i,B)) + + ! A-nb(B) distance ! + ranb2(i) = sum(dranb(1:3,i)**2) + ranb(i) = sqrt(ranb2(i)) + + ! B-nb(B) distance ! + rbnb2(i) = sum(drbnb(1:3,i)**2) + rbnb(i) = sqrt(rbnb2(i)) + end do + + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp: A-H...B ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! out-of-line damp: A...nb(B)-B ! + do i=1,nbb + ranbprbnb(i)=ranb(i)+rbnb(i)+1.d-12 + expo_nb(i)=(param%hbnbcut/radab)*(ranbprbnb(i)/rab-1.d0) + ratio2_nb(i)=exp(-expo_nb(i)) + outl_nb(i)=( 2.d0/(1.d0+ratio2_nb(i)) ) - 1.0d0 + end do + outl_nb_tot = product(outl_nb) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**6 + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) + rbhdamp = damp * ( (p_bh/rbh2/rbh) ) + rabdamp = damp * ( (p_ab/rab2/rab) ) + rdamp = rbhdamp + rabdamp + + ! set up torsion parameter ! + j = 0 + do i = 1,nbc + if( topo%nb(i,C) == B ) cycle + j = j + 1 + tlist(1,j)=topo%nb(i,C) + tlist(2,j)=B + tlist(3,j)=C + tlist(4,j)=H + tlist(5,j)=2 + t0=180 + phi0=t0*pi/180. + vtors(1,j)=phi0-(pi/2.0) + vtors(2,j)=param%tors_hb + end do + + ! calculate etors ! + do i = 1,ntors + ii =tlist(1,i) + jj =tlist(2,i) + kk =tlist(3,i) + ll =tlist(4,i) + rn =tlist(5,i) + phi0=vtors(1,i) + tshift=vtors(2,i) + phi=valijklff(n,xyz,ii,jj,kk,ll) + call egtors_nci_mul(ii,jj,kk,ll,rn,phi0,tshift,n,at,xyz,etmp(i),g4tmp(:,:,i)) + end do + etors=product(etmp(1:ntors)) + + ! calculate gtors ! + t_mask=.true. + do i = 1,ntors + t_mask(i)=.false. + ii =tlist(1,i) + jj =tlist(2,i) + kk =tlist(3,i) + ll =tlist(4,i) + gtors(1:3,ii) = gtors(1:3,ii)+g4tmp(1:3,1,i)*product(etmp(1:ntors),t_mask(1:ntors)) + gtors(1:3,jj) = gtors(1:3,jj)+g4tmp(1:3,2,i)*product(etmp(1:ntors),t_mask(1:ntors)) + gtors(1:3,kk) = gtors(1:3,kk)+g4tmp(1:3,3,i)*product(etmp(1:ntors),t_mask(1:ntors)) + gtors(1:3,ll) = gtors(1:3,ll)+g4tmp(1:3,4,i)*product(etmp(1:ntors),t_mask(1:ntors)) t_mask=.true. - do i = 1,ntors - t_mask(i)=.false. - ii =tlist(1,i) - jj =tlist(2,i) - kk =tlist(3,i) - ll =tlist(4,i) - gtors(1:3,ii) = gtors(1:3,ii)+g4tmp(1:3,1,i)*product(etmp(1:ntors),t_mask(1:ntors)) - gtors(1:3,jj) = gtors(1:3,jj)+g4tmp(1:3,2,i)*product(etmp(1:ntors),t_mask(1:ntors)) - gtors(1:3,kk) = gtors(1:3,kk)+g4tmp(1:3,3,i)*product(etmp(1:ntors),t_mask(1:ntors)) - gtors(1:3,ll) = gtors(1:3,ll)+g4tmp(1:3,4,i)*product(etmp(1:ntors),t_mask(1:ntors)) - t_mask=.true. - end do - - !Calculate eangl + gangl - r0=120 - phi0=r0*pi/180. - bshift=param%bend_hb - fc=1.0d0-bshift - call bangl(xyz,kk,jj,ll,phi) - call egbend_nci_mul(jj,kk,ll,phi0,fc,n,at,xyz,eangl,g3tmp) - gangl(1:3,jj)=gangl(1:3,jj)+g3tmp(1:3,1) - gangl(1:3,kk)=gangl(1:3,kk)+g3tmp(1:3,2) - gangl(1:3,ll)=gangl(1:3,ll)+g3tmp(1:3,3) - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - - qhoutl=qh*outl*outl_nb_tot - -! constant values, no gradient - const = ca(2)*qa*cb(1)*qb*param%xhaci_coh - -! energy - energy = -rdamp*qhoutl*eangl*etors*const - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - - aterm = -rdamp*qh*outl_nb_tot*eangl*etors*const - nbterm = -rdamp*qh*outl*eangl*etors*const - dterm = -qhoutl*eangl*etors*const - tterm = -rdamp*qhoutl*eangl*const - bterm = -rdamp*qhoutl*etors*const - -!------------------------------------------------------------------------------ -! damping part: rab - gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 - gi = gi*dterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = dg(1:3) - gb(1:3) = -dg(1:3) - -!------------------------------------------------------------------------------ -! damping part: rbh - gi = -3.d0*rbhdamp/rbh2 - gi = gi*dterm - dg(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3)+dg(1:3) - gh(1:3) = - dg(1:3) - -!------------------------------------------------------------------------------ -! angular A-H...B term -!------------------------------------------------------------------------------ -! out of line term: rab - tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - gi = -tmp1 *rahprbh/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - gi = tmp1/rah - dga(1:3) = gi*drah(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp1/rbh - dgb(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -!------------------------------------------------------------------------------ -! angular A...nb(B)-B term -!------------------------------------------------------------------------------ -! out of line term: rab + end do + + ! calculate eangl + gangl ! + r0=120 + phi0=r0*pi/180. + bshift=param%bend_hb + fc=1.0d0-bshift + call bangl(xyz,kk,jj,ll,phi) + call egbend_nci_mul(jj,kk,ll,phi0,fc,n,at,xyz,eangl,g3tmp) + gangl(1:3,jj)=gangl(1:3,jj)+g3tmp(1:3,1) + gangl(1:3,kk)=gangl(1:3,kk)+g3tmp(1:3,2) + gangl(1:3,ll)=gangl(1:3,ll)+g3tmp(1:3,3) + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + qhoutl=qh*outl*outl_nb_tot + + ! constant values, no gradient ! + const = ca(2)*qa*cb(1)*qb*param%xhaci_coh + + ! energy ! + energy = -rdamp*qhoutl*eangl*etors*const + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + + aterm = -rdamp*qh*outl_nb_tot*eangl*etors*const + nbterm = -rdamp*qh*outl*eangl*etors*const + dterm = -qhoutl*eangl*etors*const + tterm = -rdamp*qhoutl*eangl*const + bterm = -rdamp*qhoutl*etors*const + + ! damping part: rab ! + gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 + gi = gi*dterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = dg(1:3) + gb(1:3) = -dg(1:3) + + ! damping part: rbh ! + gi = -3.d0*rbhdamp/rbh2 + gi = gi*dterm + dg(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3)+dg(1:3) + gh(1:3) = - dg(1:3) + + !----------------------! + ! angular A-H...B term ! + !----------------------! + + ! out of line term: rab ! + tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + gi = -tmp1 *rahprbh/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + gi = tmp1/rah + dga(1:3) = gi*drah(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp1/rbh + dgb(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + !--------------------------! + ! angular A...nb(B)-B term ! + !--------------------------! + + ! out of line term: rab ! + mask_nb=.true. + do i=1,nbb + mask_nb(i)=.false. + tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& + & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) + gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 + dg(1:3) = gi_nb(i)*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) mask_nb=.true. - do i=1,nbb - mask_nb(i)=.false. - tmp2(i) = 2.d0*nbterm*product(outl_nb,mask_nb)*ratio2_nb(i)*expo_nb(i)/& - & (1+ratio2_nb(i))**2/(ranbprbnb(i)-rab) - gi_nb(i) = -tmp2(i) *ranbprbnb(i)/rab2 - dg(1:3) = gi_nb(i)*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - mask_nb=.true. - end do - -! out of line term: ranb,rbnb - do i=1,nbb - gi_nb(i) = tmp2(i)/ranb(i) - dga(1:3) = gi_nb(i)*dranb(1:3,i) - ga(1:3) = ga(1:3) + dga(1:3) - gi_nb(i) = tmp2(i)/rbnb(i) - dgb(1:3) = gi_nb(i)*drbnb(1:3,i) - gb(1:3) = gb(1:3) + dgb(1:3) - dgnb(1:3) = -dga(1:3)-dgb(1:3) - gnb(1:3,i) = dgnb(1:3) - end do - -!------------------------------------------------------------------------------ - if(nbb.lt.1) then - gdr(1:3,A) = gdr(1:3,A) + ga(1:3) - gdr(1:3,B) = gdr(1:3,B) + gb(1:3) - gdr(1:3,H) = gdr(1:3,H) + gh(1:3) - return - endif - -!------------------------------------------------------------------------------ -! torsion term H...B=C Case 3: A-H...B, B is 0=C including two in plane LPs at B +!> this is the multiplicative version of incorporationg etors and ebend without neighbor LP subroutine abhgfnff_eg3_mul(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - use xtb_mctc_constants - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,C,D,n,at(n) - real*8 xyz(3,n),energy,gdr(3,n) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp - real*8 ddamp,rabdamp,rbhdamp - real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) - real*8 drah(3),drbh(3),drab(3),drm(3) - real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) - real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) - real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) - real*8 phi,phi0,r0,fc,tshift,bshift - real*8 eangl,etors,gangl(3,n),gtors(3,n) - real*8 etmp,g3tmp(3,3),g4tmp(3,4) - real*8 denom,ratio,qhoutl,radab - real*8 gi,gi_nb(topo%nb(20,B)) - real*8 tmp1,tmp2(topo%nb(20,B)) - real*8 rahprbh,ranbprbnb(topo%nb(20,B)) - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) - real*8 eabh - real*8 aterm,dterm,bterm,tterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 shortcut - real*8 const - real*8 tlist(5,topo%nb(20,topo%nb(1,B))) - real*8 vtors(2,topo%nb(20,topo%nb(1,B))) - real*8 valijklff - logical mask_nb(topo%nb(20,B)) - -! proportion between Rbh und Rab distance dependencies - real*8 :: p_bh - real*8 :: p_ab - - integer i,j,ii,jj,kk,ll,ij,lina - integer nbb,nbc - integer ntors,rn - - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - p_bh=1.d0+param%hbabmix - p_ab= -param%hbabmix - - gdr = 0 - energy = 0 - etors = 0 - gtors = 0 - eangl = 0 - gangl = 0 - - call hbonds(A,B,ca,cb,param,topo) - - !Determine all neighbors for torsion term - ! A - ! \ tors: - ! H ll - ! : \ - ! O jj - ! || | - ! C kk - ! / \ \ - ! R1 R2 ii - !------------------------------------------ - nbb=topo%nb(20,B) - C=topo%nb(nbb,B) - nbc=topo%nb(20,C) - ntors=nbc-nbb - - !A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - - !A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - - !B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp: A-H...B - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**param%hbalp - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) - rbhdamp = damp * ( (p_bh/rbh2/rbh) ) - rabdamp = damp * ( (p_ab/rab2/rab) ) - rdamp = rbhdamp + rabdamp - - !Set up torsion paramter - j = 0 - do i = 1,nbc - if( topo%nb(i,C) == B ) cycle - j = j + 1 - tlist(1,j)=topo%nb(i,C) - tlist(2,j)=B - tlist(3,j)=C - tlist(4,j)=H - tlist(5,j)=2 - vtors(1,j)=pi/2.0 - vtors(2,j)=0.70 - end do - - !Calculate etors - do i = 1,ntors - ii =tlist(1,i) - jj =tlist(2,i) - kk =tlist(3,i) - ll =tlist(4,i) - rn =tlist(5,i) - phi0=vtors(1,i) - tshift=vtors(2,i) - phi=valijklff(n,xyz,ii,jj,kk,ll) - call egtors_nci_mul(ii,jj,kk,ll,rn,phi0,tshift,n,at,xyz,etmp,g4tmp) - gtors(1:3,ii) = gtors(1:3,ii)+g4tmp(1:3,1) - gtors(1:3,jj) = gtors(1:3,jj)+g4tmp(1:3,2) - gtors(1:3,kk) = gtors(1:3,kk)+g4tmp(1:3,3) - gtors(1:3,ll) = gtors(1:3,ll)+g4tmp(1:3,4) - etors = etors + etmp - end do - etors=etors/ntors - - r0=120 - phi0=r0*pi/180. - bshift=0.1 - fc=1.0d0-bshift - call bangl(xyz,kk,jj,ll,phi) - call egbend_nci_mul(jj,kk,ll,phi0,fc,n,at,xyz,etmp,g3tmp) - gangl(1:3,jj)=gangl(1:3,jj)+g3tmp(1:3,1) - gangl(1:3,kk)=gangl(1:3,kk)+g3tmp(1:3,2) - gangl(1:3,ll)=gangl(1:3,ll)+g3tmp(1:3,3) - eangl=eangl+etmp - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - -! max distance to neighbors excluded, would lead to linear C=O-H - qhoutl=qh*outl - -! constant values, no gradient - const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh - -! energy - energy = -rdamp*qhoutl*const*eangl*etors - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - - aterm = -rdamp*qh*etors*eangl*const - dterm = -qhoutl*etors*eangl*const - tterm = -rdamp*qhoutl*eangl*const/ntors - bterm = -rdamp*qhoutl*etors*const - -!------------------------------------------------------------------------------ -! damping part: rab - gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 - gi = gi*dterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = dg(1:3) - gb(1:3) = -dg(1:3) - -!------------------------------------------------------------------------------ -! damping part: rbh - gi = -3.d0*rbhdamp/rbh2 - gi = gi*dterm - dg(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3)+dg(1:3) - gh(1:3) = - dg(1:3) - -!------------------------------------------------------------------------------ -! angular A-H...B term -!------------------------------------------------------------------------------ -! out of line term: rab - tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - gi = -tmp1 *rahprbh/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - gi = tmp1/rah - dga(1:3) = gi*drah(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp1/rbh - dgb(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - - -!------------------------------------------------------------------------------ -! torsion term H...B=C squared dist + real*8 sqrab(n*(n+1)/2) + + !> dist + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ddamp,rabdamp,rbhdamp + real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) + real*8 drah(3),drbh(3),drab(3),drm(3) + real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) + real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) + real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) + real*8 phi,phi0,r0,fc,tshift,bshift + real*8 eangl,etors,gangl(3,n),gtors(3,n) + real*8 etmp,g3tmp(3,3),g4tmp(3,4) + real*8 denom,ratio,qhoutl,radab + real*8 gi,gi_nb(topo%nb(20,B)) + real*8 tmp1,tmp2(topo%nb(20,B)) + real*8 rahprbh,ranbprbnb(topo%nb(20,B)) + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) + real*8 eabh + real*8 aterm,dterm,bterm,tterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 shortcut + real*8 const + real*8 tlist(5,topo%nb(20,topo%nb(1,B))) + real*8 vtors(2,topo%nb(20,topo%nb(1,B))) + real*8 valijklff + logical mask_nb(topo%nb(20,B)) + + !> proportion between Rbh und Rab distance dependencies + real*8 :: p_bh + real*8 :: p_ab + + integer i,j,ii,jj,kk,ll,ij,lina + integer nbb,nbc + integer ntors,rn + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + p_bh=1.d0+param%hbabmix + p_ab= -param%hbabmix + + gdr = 0 + energy = 0 + etors = 0 + gtors = 0 + eangl = 0 + gangl = 0 + + call hbonds(A,B,ca,cb,param,topo) + + ! determine all neighbors for torsion term ! + ! A ! + ! \ tors: ! + ! H ll ! + ! : \ ! + ! O jj ! + ! || | ! + ! C kk ! + ! / \ \ ! + ! R1 R2 ii ! + !------------------------------------------! + + nbb=topo%nb(20,B) + C=topo%nb(nbb,B) + nbc=topo%nb(20,C) + ntors=nbc-nbb + + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp: A-H...B ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**param%hbalp + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) + rbhdamp = damp * ( (p_bh/rbh2/rbh) ) + rabdamp = damp * ( (p_ab/rab2/rab) ) + rdamp = rbhdamp + rabdamp + + ! set up torsion parameter ! + j = 0 + do i = 1,nbc + if( topo%nb(i,C) == B ) cycle + j = j + 1 + tlist(1,j)=topo%nb(i,C) + tlist(2,j)=B + tlist(3,j)=C + tlist(4,j)=H + tlist(5,j)=2 + vtors(1,j)=pi/2.0 + vtors(2,j)=0.70 + end do + + ! calculate etors ! + do i = 1,ntors + ii =tlist(1,i) + jj =tlist(2,i) + kk =tlist(3,i) + ll =tlist(4,i) + rn =tlist(5,i) + phi0=vtors(1,i) + tshift=vtors(2,i) + phi=valijklff(n,xyz,ii,jj,kk,ll) + call egtors_nci_mul(ii,jj,kk,ll,rn,phi0,tshift,n,at,xyz,etmp,g4tmp) + gtors(1:3,ii) = gtors(1:3,ii)+g4tmp(1:3,1) + gtors(1:3,jj) = gtors(1:3,jj)+g4tmp(1:3,2) + gtors(1:3,kk) = gtors(1:3,kk)+g4tmp(1:3,3) + gtors(1:3,ll) = gtors(1:3,ll)+g4tmp(1:3,4) + etors = etors + etmp + end do + etors=etors/ntors + + r0=120 + phi0=r0*pi/180. + bshift=0.1 + fc=1.0d0-bshift + call bangl(xyz,kk,jj,ll,phi) + call egbend_nci_mul(jj,kk,ll,phi0,fc,n,at,xyz,etmp,g3tmp) + gangl(1:3,jj)=gangl(1:3,jj)+g3tmp(1:3,1) + gangl(1:3,kk)=gangl(1:3,kk)+g3tmp(1:3,2) + gangl(1:3,ll)=gangl(1:3,ll)+g3tmp(1:3,3) + eangl=eangl+etmp + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + ! max distance to neighbors excluded, would lead to linear C=O-H ! + qhoutl=qh*outl + + ! constant values, no gradient ! + const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh + + ! energy ! + energy = -rdamp*qhoutl*const*eangl*etors + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + + aterm = -rdamp*qh*etors*eangl*const + dterm = -qhoutl*etors*eangl*const + tterm = -rdamp*qhoutl*eangl*const/ntors + bterm = -rdamp*qhoutl*etors*const + + ! damping part: rab ! + gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 + gi = gi*dterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = dg(1:3) + gb(1:3) = -dg(1:3) + + ! damping part: rbh ! + gi = -3.d0*rbhdamp/rbh2 + gi = gi*dterm + dg(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3)+dg(1:3) + gh(1:3) = - dg(1:3) + + !----------------------! + ! angular A-H...B term ! + !----------------------! + + ! out of line term: rab ! + tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + gi = -tmp1 *rahprbh/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + gi = tmp1/rah + dga(1:3) = gi*drah(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp1/rbh + dgb(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + + !----------------------------! + ! torsion term H...B=C Case 3: A-H...B, B is 0=C including two in plane LPs at B +!> this is the additive version of incorporationg etors and ebend subroutine abhgfnff_eg3_add(n,A,B,H,at,xyz,q,sqrab,srab,energy,gdr,param,topo) - use xtb_mctc_constants - implicit none - type(TGFFData), intent(in) :: param - type(TGFFTopology), intent(in) :: topo - integer A,B,H,C,D,n,at(n) - real*8 xyz(3,n),energy,gdr(3,n) - real*8 q(n) - real*8 sqrab(n*(n+1)/2) ! squared dist - real*8 srab(n*(n+1)/2) ! dist - - real*8 outl,dampl,damps,rdamp,damp - real*8 ddamp,rabdamp,rbhdamp - real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 - real*8 xm,ym,zm - real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 - real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) - real*8 drah(3),drbh(3),drab(3),drm(3) - real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) - real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) - real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) - real*8 phi,phi0,r0,fc - real*8 eangl,etors - real*8 etmp,g3tmp(3,3),g4tmp(3,4) - real*8 denom,ratio,qhoutl,radab - real*8 gi,gi_nb(topo%nb(20,B)) - real*8 tmp1,tmp2(topo%nb(20,B)) - real*8 rahprbh,ranbprbnb(topo%nb(20,B)) - real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) - real*8 eabh - real*8 aterm,dterm,nbterm - real*8 qa,qb,qh - real*8 ca(2),cb(2) - real*8 gqa,gqb,gqh - real*8 shortcut - real*8 const - real*8 outl_nb(topo%nb(20,B)),outl_nb_tot - real*8 tlist(5,topo%nb(20,topo%nb(1,B))) - real*8 vtors(2,topo%nb(20,topo%nb(1,B))) - real*8 valijklff - logical mask_nb(topo%nb(20,B)) - -! proportion between Rbh und Rab distance dependencies - real*8 :: p_bh - real*8 :: p_ab - - integer i,j,ii,jj,kk,ll,ij,lina - integer nbb,nbc - integer ntors,rn - - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - p_bh=1.d0+param%hbabmix - p_ab= -param%hbabmix - - gdr = 0 - energy = 0 - etors = 0 - eangl = 0 - - call hbonds(A,B,ca,cb,param,topo) - - !Determine all neighbors for torsion term - ! A - ! \ tors: - ! H ll - ! : \ - ! O jj - ! || | - ! C kk - ! / \ \ - ! R1 R2 ii - !------------------------------------------ - nbb=topo%nb(20,B) - C=topo%nb(nbb,B) - nbc=topo%nb(20,C) - ntors=nbc-nbb - - !A-B distance - ij=lina(A,B) - rab2=sqrab(ij) - rab =srab (ij) - - !A-H distance - ij=lina(A,H) - rah2= sqrab(ij) - rah = srab (ij) - - !B-H distance - ij=lina(B,H) - rbh2= sqrab(ij) - rbh = srab (ij) - - rahprbh=rah+rbh+1.d-12 - radab=param%rad(at(A))+param%rad(at(B)) - -! out-of-line damp: A-H...B - expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2=exp(expo) - outl=2.d0/(1.d0+ratio2) - -! long damping - ratio1=(rab2/param%hblongcut)**param%hbalp - dampl=1.d0/(1.d0+ratio1) - -! short damping - shortcut=param%hbscut*radab - ratio3=(shortcut/rab2)**param%hbalp - damps=1.d0/(1.d0+ratio3) - - damp = damps*dampl - ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) - rbhdamp = damp * ( (p_bh/rbh2/rbh) ) - rabdamp = damp * ( (p_ab/rab2/rab) ) - rdamp = rbhdamp + rabdamp - - !Set up torsion paramter - j = 0 - do i = 1,nbc - if( topo%nb(i,C) == B ) cycle - j = j + 1 - tlist(1,j)=topo%nb(i,C) - tlist(2,j)=B - tlist(3,j)=C - tlist(4,j)=H - tlist(5,j)=2 - vtors(1,j)=pi - vtors(2,j)=0.30 - end do - - !Calculate etors - !write(*,*)'torsion atoms nrot phi0 phi FC' - do i = 1,ntors - ii =tlist(1,i) - jj =tlist(2,i) - kk =tlist(3,i) - ll =tlist(4,i) - rn=tlist(5,i) - phi0=vtors(1,i) - fc=vtors(2,i) - phi=valijklff(n,xyz,ii,jj,kk,ll) - call egtors_nci(ii,jj,kk,ll,rn,phi0,fc,n,at,xyz,etmp,g4tmp,param) - gdr(1:3,ii) = gdr(1:3,ii)+g4tmp(1:3,1) - gdr(1:3,jj) = gdr(1:3,jj)+g4tmp(1:3,2) - gdr(1:3,kk) = gdr(1:3,kk)+g4tmp(1:3,3) - gdr(1:3,ll) = gdr(1:3,ll)+g4tmp(1:3,4) - etors = etors + etmp - end do - - !Calculate eangl + gangl - write(*,*)'angle atoms phi0 phi FC' - r0=120 - phi0=r0*pi/180. - fc=0.20 - call bangl(xyz,kk,jj,ll,phi) - write(*,'(3i5,2x,3f8.3)') & - & jj,kk,ll,phi0*180./pi,phi*180./pi,fc - call egbend_nci(jj,kk,ll,phi0,fc,n,at,xyz,etmp,g3tmp,param) - gdr(1:3,jj)=gdr(1:3,jj)+g3tmp(1:3,1) - gdr(1:3,kk)=gdr(1:3,kk)+g3tmp(1:3,2) - gdr(1:3,ll)=gdr(1:3,ll)+g3tmp(1:3,3) - eangl=eangl+etmp - -! hydrogen charge scaled term - ex1h=exp(param%hbst*q(H)) - ex2h=ex1h+param%hbsf - qh=ex1h/ex2h - -! hydrogen charge scaled term - ex1a=exp(-param%hbst*q(A)) - ex2a=ex1a+param%hbsf - qa=ex1a/ex2a - -! hydrogen charge scaled term - ex1b=exp(-param%hbst*q(B)) - ex2b=ex1b+param%hbsf - qb=ex1b/ex2b - -! max distance to neighbors excluded, would lead to linear C=O-H - qhoutl=qh*outl - -! constant values, no gradient - const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh - -! energy - energy = -rdamp*qhoutl*const+etors+eangl - -! gradient - drah(1:3)=xyz(1:3,A)-xyz(1:3,H) - drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) - drab(1:3)=xyz(1:3,A)-xyz(1:3,B) - - aterm = -rdamp*qh*const - dterm = -qhoutl*const - -!------------------------------------------------------------------------------ -! damping part: rab - gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 - gi = gi*dterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = dg(1:3) - gb(1:3) = -dg(1:3) - -!------------------------------------------------------------------------------ -! damping part: rbh - gi = -3.d0*rbhdamp/rbh2 - gi = gi*dterm - dg(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3)+dg(1:3) - gh(1:3) = - dg(1:3) - -!------------------------------------------------------------------------------ -! angular A-H...B term -!------------------------------------------------------------------------------ -! out of line term: rab - tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) - gi = -tmp1 *rahprbh/rab2 - dg(1:3) = gi*drab(1:3) - ga(1:3) = ga(1:3) + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rah,rbh - gi = tmp1/rah - dga(1:3) = gi*drah(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = tmp1/rbh - dgb(1:3) = gi*drbh(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgh(1:3) = -dga(1:3)-dgb(1:3) - gh(1:3) = gh(1:3) + dgh(1:3) - -!------------------------------------------------------------------------------ -! move gradients into place - gdr(1:3,A) = gdr(1:3,A) + ga(1:3) - gdr(1:3,B) = gdr(1:3,B) + gb(1:3) - gdr(1:3,H) = gdr(1:3,H) + gh(1:3) + + use xtb_mctc_constants + implicit none + + type(TGFFData), intent(in) :: param + type(TGFFTopology), intent(in) :: topo + integer A,B,H,C,D,n,at(n) + real*8 xyz(3,n),energy,gdr(3,n) + real*8 q(n) + + !> squared dist + real*8 sqrab(n*(n+1)/2) + + !> dist + real*8 srab(n*(n+1)/2) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ddamp,rabdamp,rbhdamp + real*8 ratio1,ratio2,ratio2_nb(topo%nb(20,B)),ratio3 + real*8 xm,ym,zm + real*8 rab,rah,rbh,rab2,rah2,rbh2,rah4,rbh4 + real*8 ranb(topo%nb(20,B)),ranb2(topo%nb(20,B)),rbnb(topo%nb(20,B)),rbnb2(topo%nb(20,B)) + real*8 drah(3),drbh(3),drab(3),drm(3) + real*8 dranb(3,topo%nb(20,B)),drbnb(3,topo%nb(20,B)) + real*8 dg(3),dga(3),dgb(3),dgh(3),dgnb(3) + real*8 ga(3),gb(3),gh(3),gnb(3,topo%nb(20,B)) + real*8 phi,phi0,r0,fc + real*8 eangl,etors + real*8 etmp,g3tmp(3,3),g4tmp(3,4) + real*8 denom,ratio,qhoutl,radab + real*8 gi,gi_nb(topo%nb(20,B)) + real*8 tmp1,tmp2(topo%nb(20,B)) + real*8 rahprbh,ranbprbnb(topo%nb(20,B)) + real*8 ex1a,ex2a,ex1b,ex2b,ex1h,ex2h,expo,expo_nb(topo%nb(20,B)) + real*8 eabh + real*8 aterm,dterm,nbterm + real*8 qa,qb,qh + real*8 ca(2),cb(2) + real*8 gqa,gqb,gqh + real*8 shortcut + real*8 const + real*8 outl_nb(topo%nb(20,B)),outl_nb_tot + real*8 tlist(5,topo%nb(20,topo%nb(1,B))) + real*8 vtors(2,topo%nb(20,topo%nb(1,B))) + real*8 valijklff + logical mask_nb(topo%nb(20,B)) + + !> proportion between Rbh und Rab distance dependencies + real*8 :: p_bh + real*8 :: p_ab + + integer i,j,ii,jj,kk,ll,ij,lina + integer nbb,nbc + integer ntors,rn + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + p_bh=1.d0+param%hbabmix + p_ab= -param%hbabmix + + gdr = 0 + energy = 0 + etors = 0 + eangl = 0 + + call hbonds(A,B,ca,cb,param,topo) + + ! determine all neighbors for torsion term ! + ! A ! + ! \ tors: ! + ! H ll ! + ! : \ ! + ! O jj ! + ! || | ! + ! C kk ! + ! / \ \ ! + ! R1 R2 ii ! + !------------------------------------------! + + nbb=topo%nb(20,B) + C=topo%nb(nbb,B) + nbc=topo%nb(20,C) + ntors=nbc-nbb + + ! A-B distance ! + ij=lina(A,B) + rab2=sqrab(ij) + rab =srab (ij) + + ! A-H distance ! + ij=lina(A,H) + rah2= sqrab(ij) + rah = srab (ij) + + ! B-H distance ! + ij=lina(B,H) + rbh2= sqrab(ij) + rbh = srab (ij) + + rahprbh=rah+rbh+1.d-12 + radab=param%rad(at(A))+param%rad(at(B)) + + ! out-of-line damp: A-H...B ! + expo=(param%hbacut/radab)*(rahprbh/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2=exp(expo) + outl=2.d0/(1.d0+ratio2) + + ! long damping ! + ratio1=(rab2/param%hblongcut)**param%hbalp + dampl=1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut=param%hbscut*radab + ratio3=(shortcut/rab2)**param%hbalp + damps=1.d0/(1.d0+ratio3) + + damp = damps*dampl + ddamp = (-2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3/(1.d0+ratio3)) + rbhdamp = damp * ( (p_bh/rbh2/rbh) ) + rabdamp = damp * ( (p_ab/rab2/rab) ) + rdamp = rbhdamp + rabdamp + + ! set up torsion paramter ! + j = 0 + do i = 1,nbc + if( topo%nb(i,C) == B ) cycle + j = j + 1 + tlist(1,j)=topo%nb(i,C) + tlist(2,j)=B + tlist(3,j)=C + tlist(4,j)=H + tlist(5,j)=2 + vtors(1,j)=pi + vtors(2,j)=0.30 + end do + + ! calculate etors ! + do i = 1,ntors + ii =tlist(1,i) + jj =tlist(2,i) + kk =tlist(3,i) + ll =tlist(4,i) + rn=tlist(5,i) + phi0=vtors(1,i) + fc=vtors(2,i) + phi=valijklff(n,xyz,ii,jj,kk,ll) + call egtors_nci(ii,jj,kk,ll,rn,phi0,fc,n,at,xyz,etmp,g4tmp,param) + gdr(1:3,ii) = gdr(1:3,ii)+g4tmp(1:3,1) + gdr(1:3,jj) = gdr(1:3,jj)+g4tmp(1:3,2) + gdr(1:3,kk) = gdr(1:3,kk)+g4tmp(1:3,3) + gdr(1:3,ll) = gdr(1:3,ll)+g4tmp(1:3,4) + etors = etors + etmp + end do + + ! calculate eangl + gangl ! + write(*,*)'angle atoms phi0 phi FC' + r0=120 + phi0=r0*pi/180. + fc=0.20 + call bangl(xyz,kk,jj,ll,phi) + write(*,'(3i5,2x,3f8.3)') & + & jj,kk,ll,phi0*180./pi,phi*180./pi,fc + call egbend_nci(jj,kk,ll,phi0,fc,n,at,xyz,etmp,g3tmp,param) + gdr(1:3,jj)=gdr(1:3,jj)+g3tmp(1:3,1) + gdr(1:3,kk)=gdr(1:3,kk)+g3tmp(1:3,2) + gdr(1:3,ll)=gdr(1:3,ll)+g3tmp(1:3,3) + eangl=eangl+etmp + + ! hydrogen charge scaled term ! + ex1h=exp(param%hbst*q(H)) + ex2h=ex1h+param%hbsf + qh=ex1h/ex2h + + ! hydrogen charge scaled term ! + ex1a=exp(-param%hbst*q(A)) + ex2a=ex1a+param%hbsf + qa=ex1a/ex2a + + ! hydrogen charge scaled term ! + ex1b=exp(-param%hbst*q(B)) + ex2b=ex1b+param%hbsf + qb=ex1b/ex2b + + ! max distance to neighbors excluded, would lead to linear C=O-H ! + qhoutl=qh*outl + + ! constant values, no gradient ! + const = ca(2)*qa*cb(1)*qb*param%xhaci_globabh + + ! energy ! + energy = -rdamp*qhoutl*const+etors+eangl + + ! gradient ! + drah(1:3)=xyz(1:3,A)-xyz(1:3,H) + drbh(1:3)=xyz(1:3,B)-xyz(1:3,H) + drab(1:3)=xyz(1:3,A)-xyz(1:3,B) + + aterm = -rdamp*qh*const + dterm = -qhoutl*const + + ! damping part: rab ! + gi = ( (rabdamp+rbhdamp)*ddamp-3.d0*rabdamp ) / rab2 + gi = gi*dterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = dg(1:3) + gb(1:3) = -dg(1:3) + + ! damping part: rbh ! + gi = -3.d0*rbhdamp/rbh2 + gi = gi*dterm + dg(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3)+dg(1:3) + gh(1:3) = - dg(1:3) + + !----------------------! + ! angular A-H...B term ! + !----------------------! + + ! out of line term: rab ! + tmp1 = -2.d0*aterm*ratio2*expo/(1+ratio2)**2/(rahprbh-rab) + gi = -tmp1 *rahprbh/rab2 + dg(1:3) = gi*drab(1:3) + ga(1:3) = ga(1:3) + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rah,rbh ! + gi = tmp1/rah + dga(1:3) = gi*drah(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = tmp1/rbh + dgb(1:3) = gi*drbh(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgh(1:3) = -dga(1:3)-dgb(1:3) + gh(1:3) = gh(1:3) + dgh(1:3) + + ! move gradients into place ! + gdr(1:3,A) = gdr(1:3,A) + ga(1:3) + gdr(1:3,B) = gdr(1:3,B) + gb(1:3) + gdr(1:3,H) = gdr(1:3,H) + gh(1:3) end subroutine abhgfnff_eg3_add -!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc -! XB energy and analytical gradient -!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc - +!> XB energy and analytical gradient subroutine rbxgfnff_eg(n,A,B,X,at,xyz,q,energy,gdr,param) - implicit none - type(TGFFData), intent(in) :: param - integer :: A,B,X,n,at(n) - real*8 :: xyz(3,n) - real*8,intent(inout) :: energy,gdr(3,3) - real*8 :: q(n) - - real*8 outl,dampl,damps,rdamp,damp - real*8 ratio1,ratio2,ratio3 - real*8 rab,rax,rbx,rab2,rax2,rbx2,rax4,rbx4 - real*8 drax(3),drbx(3),drab(3),drm(3) - real*8 dg(3),dga(3),dgb(3),dgx(3) - real*8 gi,ga(3),gb(3),gx(3) - real*8 ex1_a,ex2_a,ex1_b,ex2_b,ex1_x,ex2_x,expo - real*8 aterm,dterm - real*8 qa,qb,qx - real*8 cx,cb - real*8 gqa,gqb,gqx - real*8 shortcut,const - - integer i,j - - gdr = 0 - energy=0 - - cb = 1.!param%xhbas(at(B)) - cx = param%xbaci(at(X)) - -! compute distances - drax(1:3) = xyz(1:3,A)-xyz(1:3,X) - drbx(1:3) = xyz(1:3,B)-xyz(1:3,X) - drab(1:3) = xyz(1:3,A)-xyz(1:3,B) - -! A-B distance - rab2 = sum(drab**2) - rab = sqrt(rab2) - -! A-X distance - rax2 = sum(drax**2) - rax = sqrt(rax2)+1.d-12 - -! B-X distance - rbx2 = sum(drbx**2) - rbx = sqrt(rbx2)+1.d-12 - -! out-of-line damp - expo = param%xbacut*((rax+rbx)/rab-1.d0) - if(expo.gt.15.0d0) return ! avoid overflow - ratio2 = exp(expo) - outl = 2.d0/(1.d0+ratio2) - -! long damping - ratio1 = (rbx2/param%hblongcut_xb)**param%hbalp - dampl = 1.d0/(1.d0+ratio1) - -! short damping - shortcut = param%xbscut*(param%rad(at(A))+param%rad(at(B))) - ratio3 = (shortcut/rbx2)**param%hbalp - damps = 1.d0/(1.d0+ratio3) - - damp = damps*dampl - rdamp = damp/rbx2/rbx ! **2 - -! halogen charge scaled term - ex1_x = exp(param%xbst*q(X)) - ex2_x = ex1_x+param%xbsf - qx = ex1_x/ex2_x - -! donor charge scaled term - ex1_b = exp(-param%xbst*q(B)) - ex2_b = ex1_b+param%xbsf - qb = ex1_b/ex2_b - -! constant values, no gradient - const = cb*qb*cx*qx - -! r^3 only sligxtly better than r^4 - aterm = -rdamp*const - dterm = -outl*const - energy= -rdamp*outl*const - -! damping part rab - gi = rdamp*(-(2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3& - & /(1.d0+ratio3))-3.d0)/rbx2 ! 4,5,6 instead of 3. - gi = gi*dterm - dg(1:3) = gi*drbx(1:3) - gb(1:3) = dg(1:3) - gx(1:3) = -dg(1:3) - -! out of line term: rab - gi =2.d0*ratio2*expo*(rax+rbx)/(1.d0+ratio2)**2/(rax+rbx-rab)/rab2 - gi = gi*aterm - dg(1:3) = gi*drab(1:3) - ga(1:3) = + dg(1:3) - gb(1:3) = gb(1:3) - dg(1:3) - -! out of line term: rax,rbx - gi = -2.d0*ratio2*expo/(1.d0+ratio2)**2/(rax+rbx-rab)/rax - gi = gi*aterm - dga(1:3) = gi*drax(1:3) - ga(1:3) = ga(1:3) + dga(1:3) - gi = -2.d0*ratio2*expo/(1.d0+ratio2)**2/(rax+rbx-rab)/rbx - gi = gi*aterm - dgb(1:3) = gi*drbx(1:3) - gb(1:3) = gb(1:3) + dgb(1:3) - dgx(1:3) = -dga(1:3) - dgb(1:3) - gx(1:3) = gx(1:3) + dgx(1:3) - -! move gradients into place - - gdr(1:3,1) = ga(1:3) - gdr(1:3,2) = gb(1:3) - gdr(1:3,3) = gx(1:3) - - return - end subroutine rbxgfnff_eg - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! taken from D3 ATM code -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - + + implicit none + type(TGFFData), intent(in) :: param + integer :: A,B,X,n,at(n) + real*8 :: xyz(3,n) + real*8,intent(inout) :: energy,gdr(3,3) + real*8 :: q(n) + + real*8 outl,dampl,damps,rdamp,damp + real*8 ratio1,ratio2,ratio3 + real*8 rab,rax,rbx,rab2,rax2,rbx2,rax4,rbx4 + real*8 drax(3),drbx(3),drab(3),drm(3) + real*8 dg(3),dga(3),dgb(3),dgx(3) + real*8 gi,ga(3),gb(3),gx(3) + real*8 ex1_a,ex2_a,ex1_b,ex2_b,ex1_x,ex2_x,expo + real*8 aterm,dterm + real*8 qa,qb,qx + real*8 cx,cb + real*8 gqa,gqb,gqx + real*8 shortcut,const + + integer i,j + + gdr = 0 + energy=0 + + cb = 1. ! param%xhbas(at(B)) ! + cx = param%xbaci(at(X)) + + ! compute distances ! + drax(1:3) = xyz(1:3,A)-xyz(1:3,X) + drbx(1:3) = xyz(1:3,B)-xyz(1:3,X) + drab(1:3) = xyz(1:3,A)-xyz(1:3,B) + + ! A-B distance ! + rab2 = sum(drab**2) + rab = sqrt(rab2) + + ! A-X distance ! + rax2 = sum(drax**2) + rax = sqrt(rax2)+1.d-12 + + ! B-X distance ! + rbx2 = sum(drbx**2) + rbx = sqrt(rbx2)+1.d-12 + + ! out-of-line damp ! + expo = param%xbacut*((rax+rbx)/rab-1.d0) + if(expo.gt.15.0d0) return ! avoid overflow ! + ratio2 = exp(expo) + outl = 2.d0/(1.d0+ratio2) + + ! long damping ! + ratio1 = (rbx2/param%hblongcut_xb)**param%hbalp + dampl = 1.d0/(1.d0+ratio1) + + ! short damping ! + shortcut = param%xbscut*(param%rad(at(A))+param%rad(at(B))) + ratio3 = (shortcut/rbx2)**param%hbalp + damps = 1.d0/(1.d0+ratio3) + + damp = damps*dampl + rdamp = damp/rbx2/rbx ! **2 + + ! halogen charge scaled term ! + ex1_x = exp(param%xbst*q(X)) + ex2_x = ex1_x+param%xbsf + qx = ex1_x/ex2_x + + ! donor charge scaled term ! + ex1_b = exp(-param%xbst*q(B)) + ex2_b = ex1_b+param%xbsf + qb = ex1_b/ex2_b + + ! constant values, no gradient ! + const = cb*qb*cx*qx + + ! r^3 only sligxtly better than r^4 ! + aterm = -rdamp*const + dterm = -outl*const + energy= -rdamp*outl*const + + ! damping part rab ! + gi = rdamp*(-(2.d0*param%hbalp*ratio1/(1.d0+ratio1))+(2.d0*param%hbalp*ratio3& + & /(1.d0+ratio3))-3.d0)/rbx2 ! 4,5,6 instead of 3 ! + gi = gi*dterm + dg(1:3) = gi*drbx(1:3) + gb(1:3) = dg(1:3) + gx(1:3) = -dg(1:3) + + ! out of line term: rab ! + gi =2.d0*ratio2*expo*(rax+rbx)/(1.d0+ratio2)**2/(rax+rbx-rab)/rab2 + gi = gi*aterm + dg(1:3) = gi*drab(1:3) + ga(1:3) = + dg(1:3) + gb(1:3) = gb(1:3) - dg(1:3) + + ! out of line term: rax,rbx ! + gi = -2.d0*ratio2*expo/(1.d0+ratio2)**2/(rax+rbx-rab)/rax + gi = gi*aterm + dga(1:3) = gi*drax(1:3) + ga(1:3) = ga(1:3) + dga(1:3) + gi = -2.d0*ratio2*expo/(1.d0+ratio2)**2/(rax+rbx-rab)/rbx + gi = gi*aterm + dgb(1:3) = gi*drbx(1:3) + gb(1:3) = gb(1:3) + dgb(1:3) + dgx(1:3) = -dga(1:3) - dgb(1:3) + gx(1:3) = gx(1:3) + dgx(1:3) + + ! move gradients into place ! + gdr(1:3,1) = ga(1:3) + gdr(1:3,2) = gb(1:3) + gdr(1:3,3) = gx(1:3) + + return + +end subroutine rbxgfnff_eg + +!> taken from D3 ATM code subroutine batmgfnff_eg(n,iat,jat,kat,at,xyz,q,sqrab,srab,energy,g,param) - implicit none - type(TGFFData), intent(in) :: param - integer, intent(in) :: iat,jat,kat,n,at(n) - real*8, intent(in) :: xyz(3,n),q(n) - real*8, intent(out) :: energy,g(3,3) - real*8, intent(in) :: sqrab(n*(n+1)/2) ! squared dist - real*8, intent(in) :: srab (n*(n+1)/2) ! dist - - real*8 r2ij,r2jk,r2ik,c9,mijk,imjk,ijmk,rijk3,ang,angr9,rav3 - real*8 rij(3),rik(3),rjk(3),drij,drik,drjk,dang,ff,fi,fj,fk,fqq - parameter (fqq=3.0d0) - integer linij,linik,linjk,lina,i,j - lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 - - fi=(1.d0-fqq*q(iat)) - fi=min(max(fi,-4.0d0),4.0d0) - fj=(1.d0-fqq*q(jat)) - fj=min(max(fj,-4.0d0),4.0d0) - fk=(1.d0-fqq*q(kat)) - fk=min(max(fk,-4.0d0),4.0d0) - ff=fi*fj*fk ! charge term - c9=ff*param%zb3atm(at(iat))*param%zb3atm(at(jat))*param%zb3atm(at(kat)) ! strength of interaction - linij=lina(iat,jat) - linik=lina(iat,kat) - linjk=lina(jat,kat) - r2ij=sqrab(linij) - r2jk=sqrab(linjk) - r2ik=sqrab(linik) - mijk=-r2ij+r2jk+r2ik - imjk= r2ij-r2jk+r2ik - ijmk= r2ij+r2jk-r2ik - rijk3=r2ij*r2jk*r2ik - rav3=rijk3**1.5 ! R^9 - ang=0.375d0*ijmk*imjk*mijk/rijk3 - angr9=(ang +1.0d0)/rav3 - energy=c9*angr9 ! energy - -! derivatives of each part w.r.t. r_ij,jk,ik - dang=-0.375d0*(r2ij**3+r2ij**2*(r2jk+r2ik) & - & +r2ij*(3.0d0*r2jk**2+2.0*r2jk*r2ik+3.0*r2ik**2) & - & -5.0*(r2jk-r2ik)**2*(r2jk+r2ik)) & - & /(srab(linij)*rijk3*rav3) - drij=-dang*c9 - dang=-0.375d0*(r2jk**3+r2jk**2*(r2ik+r2ij) & - & +r2jk*(3.0d0*r2ik**2+2.0*r2ik*r2ij+3.0*r2ij**2) & - & -5.0*(r2ik-r2ij)**2*(r2ik+r2ij)) & - & /(srab(linjk)*rijk3*rav3) - drjk=-dang*c9 - dang=-0.375d0*(r2ik**3+r2ik**2*(r2jk+r2ij) & - & +r2ik*(3.0d0*r2jk**2+2.0*r2jk*r2ij+3.0*r2ij**2) & - & -5.0*(r2jk-r2ij)**2*(r2jk+r2ij)) & - & /(srab(linik)*rijk3*rav3) - drik=-dang*c9 - - rij=xyz(:,jat)-xyz(:,iat) - rik=xyz(:,kat)-xyz(:,iat) - rjk=xyz(:,kat)-xyz(:,jat) - g(:,1 )= drij*rij/srab(linij) - g(:,1 )=g(:,1 )+drik*rik/srab(linik) - g(:,2 )= drjk*rjk/srab(linjk) - g(:,2 )=g(:,2 )-drij*rij/srab(linij) - g(:,3 )= -drik*rik/srab(linik) - g(:,3 )=g(:,3 )-drjk*rjk/srab(linjk) - - end subroutine batmgfnff_eg - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! torsion term for rotation around triple bonded carbon -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + implicit none + + type(TGFFData), intent(in) :: param + integer, intent(in) :: iat,jat,kat,n,at(n) + real*8, intent(in) :: xyz(3,n),q(n) + real*8, intent(out) :: energy,g(3,3) + + !> squared dist + real*8, intent(in) :: sqrab(n*(n+1)/2) + + !> distance + real*8, intent(in) :: srab (n*(n+1)/2) + + real*8 r2ij,r2jk,r2ik,c9,mijk,imjk,ijmk,rijk3,ang,angr9,rav3 + real*8 rij(3),rik(3),rjk(3),drij,drik,drjk,dang,ff,fi,fj,fk,fqq + parameter (fqq=3.0d0) + integer linij,linik,linjk,lina,i,j + + lina(i,j)=min(i,j)+max(i,j)*(max(i,j)-1)/2 + + fi=(1.d0-fqq*q(iat)) + fi=min(max(fi,-4.0d0),4.0d0) + fj=(1.d0-fqq*q(jat)) + fj=min(max(fj,-4.0d0),4.0d0) + fk=(1.d0-fqq*q(kat)) + fk=min(max(fk,-4.0d0),4.0d0) + ff=fi*fj*fk ! charge term ! + c9=ff*param%zb3atm(at(iat))*param%zb3atm(at(jat))*param%zb3atm(at(kat)) ! strength of interaction + linij=lina(iat,jat) + linik=lina(iat,kat) + linjk=lina(jat,kat) + r2ij=sqrab(linij) + r2jk=sqrab(linjk) + r2ik=sqrab(linik) + mijk=-r2ij+r2jk+r2ik + imjk= r2ij-r2jk+r2ik + ijmk= r2ij+r2jk-r2ik + rijk3=r2ij*r2jk*r2ik + rav3=rijk3**1.5 ! R^9 ! + ang=0.375d0*ijmk*imjk*mijk/rijk3 + angr9=(ang +1.0d0)/rav3 + energy=c9*angr9 ! energy ! + + ! derivatives of each part w.r.t. r_ij,jk,ik ! + dang=-0.375d0*(r2ij**3+r2ij**2*(r2jk+r2ik) & + & +r2ij*(3.0d0*r2jk**2+2.0*r2jk*r2ik+3.0*r2ik**2) & + & -5.0*(r2jk-r2ik)**2*(r2jk+r2ik)) & + & /(srab(linij)*rijk3*rav3) + drij=-dang*c9 + dang=-0.375d0*(r2jk**3+r2jk**2*(r2ik+r2ij) & + & +r2jk*(3.0d0*r2ik**2+2.0*r2ik*r2ij+3.0*r2ij**2) & + & -5.0*(r2ik-r2ij)**2*(r2ik+r2ij)) & + & /(srab(linjk)*rijk3*rav3) + drjk=-dang*c9 + dang=-0.375d0*(r2ik**3+r2ik**2*(r2jk+r2ij) & + & +r2ik*(3.0d0*r2jk**2+2.0*r2jk*r2ij+3.0*r2ij**2) & + & -5.0*(r2jk-r2ij)**2*(r2jk+r2ij)) & + & /(srab(linik)*rijk3*rav3) + drik=-dang*c9 + + rij=xyz(:,jat)-xyz(:,iat) + rik=xyz(:,kat)-xyz(:,iat) + rjk=xyz(:,kat)-xyz(:,jat) + + g(:,1 )= drij*rij/srab(linij) + g(:,1 )=g(:,1 )+drik*rik/srab(linik) + g(:,2 )= drjk*rjk/srab(linjk) + g(:,2 )=g(:,2 )-drij*rij/srab(linij) + g(:,3 )= -drik*rik/srab(linik) + g(:,3 )=g(:,3 )-drjk*rjk/srab(linjk) + +end subroutine batmgfnff_eg + +!> torsion term for rotation around triple bonded carbon subroutine sTors_eg(m, n, xyz, topo, energy, dg) -use xtb_mctc_accuracy, only : wp - integer, intent(in) :: m - integer, intent(in) :: n - real(wp), intent(in) :: xyz(3,n) - type(TGFFTopology), intent(in) :: topo - real(wp), intent(out) :: energy - real(wp), intent(out) :: dg(3,n) - integer :: c1,c2,c3,c4 - integer :: i - real(wp) :: phi, valijklff ! torsion angle between C1-C4 - real(wp) :: erefhalf - real(wp) :: dp1(3),dp2(3),dp3(3),dp4(3) - - energy = 0.0_wp - dg(:,:) = 0.0_wp - - if ( .not. any(topo%sTorsl(:,m) .eq. 0)) then - c1 = topo%sTorsl(1,m) - c2 = topo%sTorsl(2,m) - c3 = topo%sTorsl(5,m) - c4 = topo%sTorsl(6,m) - - ! dihedral angle in radians - phi=valijklff(n,xyz,c1,c2,c3,c4) - call dphidr(n,xyz,c1,c2,c3,c4,phi,dp1,dp2,dp3,dp4) - ! reference energy for torsion of 90° calculated with DLPNO-CCSD(T) CBS on diphenylacetylene - erefhalf = 3.75_wp*1.0e-4_wp ! approx 1.97 kJ/mol - energy = -erefhalf*cos(2.0_wp*phi) + erefhalf - do i=1, 3 - dg(i, c1) = dg(i, c1) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp1(i) - dg(i, c2) = dg(i, c2) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp2(i) - dg(i, c3) = dg(i, c3) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp3(i) - dg(i, c4) = dg(i, c4) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp4(i) - enddo - endif + use xtb_mctc_accuracy, only : wp + + integer, intent(in) :: m + integer, intent(in) :: n + real(wp), intent(in) :: xyz(3,n) + type(TGFFTopology), intent(in) :: topo + real(wp), intent(out) :: energy + real(wp), intent(out) :: dg(3,n) + integer :: c1,c2,c3,c4 + integer :: i + + !> torsion angle between C1-C4 + real(wp) :: phi, valijklff + real(wp) :: erefhalf + real(wp) :: dp1(3),dp2(3),dp3(3),dp4(3) + + energy = 0.0_wp + dg(:,:) = 0.0_wp + + if ( .not. any(topo%sTorsl(:,m) .eq. 0)) then + + c1 = topo%sTorsl(1,m) + c2 = topo%sTorsl(2,m) + c3 = topo%sTorsl(5,m) + c4 = topo%sTorsl(6,m) + + ! dihedral angle in radians! + phi=valijklff(n,xyz,c1,c2,c3,c4) + call dphidr(n,xyz,c1,c2,c3,c4,phi,dp1,dp2,dp3,dp4) + + ! reference energy for torsion of 90° ! + ! calculated with DLPNO-CCSD(T) CBS on diphenylacetylene ! + erefhalf = 3.75_wp*1.0e-4_wp ! approx 1.97 kJ/mol ! + energy = -erefhalf*cos(2.0_wp*phi) + erefhalf + do i=1, 3 + dg(i, c1) = dg(i, c1) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp1(i) + dg(i, c2) = dg(i, c2) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp2(i) + dg(i, c3) = dg(i, c3) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp3(i) + dg(i, c4) = dg(i, c4) + erefhalf*2.0_wp*sin(2.0_wp*phi)*dp4(i) + enddo + endif end subroutine sTors_eg -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! CN routines -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!> CN routines !> logCN derivative saved in dlogCN array subroutine gfnff_dlogcoord(n,at,xyz,rab,logCN,dlogCN,thr2,param) -use xtb_mctc_accuracy, only : wp - implicit none - type(TGFFData), intent(in) :: param - integer, intent(in) :: n - integer, intent(in) :: at(n) - real(wp),intent(in) :: xyz(3,n) - real(wp),intent(in) :: rab(n*(n+1)/2) - real(wp),intent(out) :: logCN(n) - real(wp),intent(out) :: dlogCN(3,n,n) - real(wp),intent(in) :: thr2 - real(wp) :: cn(n) - !> counter - integer :: i,j,ij,ii - !> distances - real(wp) :: r - real(wp) :: r0 - real(wp) :: dr - real(wp), dimension(3) :: rij - !> treshold - real(wp) :: thr - !> cn parameter - real(wp) :: erfCN - real(wp) :: dlogdcni - real(wp) :: dlogdcnj - real(wp) :: derivative - !> local parameter - real(wp),parameter :: kn = -7.5_wp - !> initialize vaiiables - cn = 0.0_wp - logCN = 0.0_wp - dlogCN = 0.0_wp - dlogdcni = 0.0_wp - dlogdcnj = 0.0_wp - derivative = 0.0_wp - r = 0.0_wp - r0 = 0.0_wp - rij = 0.0_wp - thr = sqrt(thr2) - !> create error function CN - do i = 2, n - ii=i*(i-1)/2 - do j = 1, i-1 - ij = ii+j - r = rab(ij) - if (r.gt.thr) cycle - r0=(param%rcov(at(i))+param%rcov(at(j))) - dr = (r-r0)/r0 - !> hier kommt die CN funktion hin -! erfCN = create_expCN(16.0d0,r,r0) - erfCN = 0.5_wp * (1.0_wp + erf(kn*dr)) - cn(i) = cn(i) + erfCN - cn(j) = cn(j) + erfCN - enddo + use xtb_mctc_accuracy, only : wp + implicit none + + type(TGFFData), intent(in) :: param + integer, intent(in) :: n + integer, intent(in) :: at(n) + real(wp),intent(in) :: xyz(3,n) + real(wp),intent(in) :: rab(n*(n+1)/2) + real(wp),intent(out) :: logCN(n) + real(wp),intent(out) :: dlogCN(3,n,n) + real(wp),intent(in) :: thr2 + real(wp) :: cn(n) + + !> counter + integer :: i,j,ij,ii + + !> distances + real(wp) :: r + + real(wp) :: r0 + real(wp) :: dr + real(wp), dimension(3) :: rij + + !> treshold + real(wp) :: thr + + !> cn parameter + real(wp) :: erfCN + + real(wp) :: dlogdcni + real(wp) :: dlogdcnj + real(wp) :: derivative + + !> local parameter + real(wp),parameter :: kn = -7.5_wp + + cn = 0.0_wp + logCN = 0.0_wp + dlogCN = 0.0_wp + dlogdcni = 0.0_wp + dlogdcnj = 0.0_wp + derivative = 0.0_wp + r = 0.0_wp + r0 = 0.0_wp + rij = 0.0_wp + thr = sqrt(thr2) + + ! create error function CN ! + do i = 2, n + ii=i*(i-1)/2 + do j = 1, i-1 + ij = ii+j + r = rab(ij) + if (r.gt.thr) cycle + r0=(param%rcov(at(i))+param%rcov(at(j))) + dr = (r-r0)/r0 + ! hier kommt die CN funktion hin ! + ! erfCN = create_expCN(16.0d0,r,r0) ! + erfCN = 0.5_wp * (1.0_wp + erf(kn*dr)) + cn(i) = cn(i) + erfCN + cn(j) = cn(j) + erfCN enddo - !> create cutted logarithm CN + derivatives - do i = 1, n - ii=i*(i-1)/2 - logCN(i) = create_logCN(cn(i),param) - !> get dlogCN/dCNi - dlogdcni = create_dlogCN(cn(i),param) - do j = 1, i-1 - ij = ii+j - !> get dlogCN/dCNj - dlogdcnj = create_dlogCN(cn(j),param) - r = rab(ij) - if (r.gt.thr) cycle - r0 = (param%rcov(at(i)) + param%rcov(at(j))) - !> get derfCN/dRij - derivative = create_derfCN(kn,r,r0) -! derivative = create_dexpCN(16.0d0,r,r0) - rij = derivative*(xyz(:,j) - xyz(:,i))/r - !> project rij gradient onto cartesians - dlogCN(:,j,j)= dlogdcnj*rij + dlogCN(:,j,j) - dlogCN(:,i,j)=-dlogdcnj*rij - dlogCN(:,j,i)= dlogdcni*rij - dlogCN(:,i,i)=-dlogdcni*rij + dlogCN(:,i,i) - enddo + enddo + + ! create cutted logarithm CN + derivatives ! + do i = 1, n + ii=i*(i-1)/2 + logCN(i) = create_logCN(cn(i),param) + + ! get dlogCN/dCNi ! + dlogdcni = create_dlogCN(cn(i),param) + do j = 1, i-1 + ij = ii+j + + ! get dlogCN/dCNj ! + dlogdcnj = create_dlogCN(cn(j),param) + r = rab(ij) + if (r.gt.thr) cycle + r0 = (param%rcov(at(i)) + param%rcov(at(j))) + + ! get derfCN/dRij ! + derivative = create_derfCN(kn,r,r0) + + ! derivative = create_dexpCN(16.0d0,r,r0) ! + rij = derivative*(xyz(:,j) - xyz(:,i))/r + + ! project rij gradient onto cartesians ! + dlogCN(:,j,j)= dlogdcnj*rij + dlogCN(:,j,j) + dlogCN(:,i,j)=-dlogdcnj*rij + dlogCN(:,j,i)= dlogdcni*rij + dlogCN(:,i,i)=-dlogdcni*rij + dlogCN(:,i,i) enddo + enddo - contains +contains pure elemental function create_logCN(cn,param) result(count) -use xtb_mctc_accuracy, only : wp - type(TGFFData), intent(in) :: param + + use xtb_mctc_accuracy, only : wp + + type(TGFFData), intent(in) :: param real(wp), intent(in) :: cn real(wp) :: count + count = log(1 + exp(param%cnmax)) - log(1 + exp(param%cnmax - cn) ) + end function create_logCN pure elemental function create_dlogCN(cn,param) result(count) -use xtb_mctc_accuracy, only : wp - type(TGFFData), intent(in) :: param + + use xtb_mctc_accuracy, only : wp + + type(TGFFData), intent(in) :: param real(wp), intent(in) :: cn real(wp) :: count + count = exp(param%cnmax)/(exp(param%cnmax) + exp(cn)) + end function create_dlogCN pure elemental function create_erfCN(k,r,r0) result(count) -use xtb_mctc_accuracy, only : wp + + use xtb_mctc_accuracy, only : wp + real(wp), intent(in) :: k real(wp), intent(in) :: r real(wp), intent(in) :: r0 real(wp) :: count real(wp) :: dr + dr = (r -r0)/r0 count = 0.5_wp * (1.0_wp + erf(kn*dr)) + end function create_erfCN pure elemental function create_derfCN(k,r,r0) result(count) -use xtb_mctc_accuracy, only : wp + + use xtb_mctc_accuracy, only : wp + real(wp), intent(in) :: k real(wp), intent(in) :: r real(wp), intent(in) :: r0 real(wp), parameter :: sqrtpi = 1.77245385091_wp real(wp) :: count real(wp) :: dr + dr = (r -r0)/r0 count = k/sqrtpi*exp(-k**2*dr*dr)/r0 + end function create_derfCN pure elemental function create_expCN(k,r,r0) result(count) + real(wp), intent(in) :: k real(wp), intent(in) :: r real(wp), intent(in) :: r0 real(wp) :: count + count =1.0_wp/(1.0_wp+exp(-k*(r0/r-1.0_wp))) + end function create_expCN pure elemental function create_dexpCN(k,r,r0) result(count) + real(wp), intent(in) :: k real(wp), intent(in) :: r real(wp), intent(in) :: r0 real(wp) :: count real(wp) :: expterm + expterm=exp(-k*(r0/r-1._wp)) count = (-k*r0*expterm)/(r**2*((expterm+1._wp)**2)) + end function create_dexpCN end subroutine gfnff_dlogcoord diff --git a/src/oniom.f90 b/src/oniom.f90 index 7a0423859..f7aa75421 100644 --- a/src/oniom.f90 +++ b/src/oniom.f90 @@ -44,40 +44,39 @@ module xtb_oniom type :: oniom_input character(len=:), allocatable :: first_arg character(len=:), allocatable :: second_arg - !character(len=:), allocatable :: chrg - !logical :: g - end type oniom_input + + end type oniom_input !> ONIOM calculator type, extends(TCalculator) :: TOniomCalculator + !> methods specified by the user, or default: gfnff, gfn2 integer :: method_low, method_high - !! methods specified by the user, or default: gfnff, gfn2 + !> charge for inner region integer :: chrg_model - !! charge for inner region - !! rewrite + ! rewrite + !> inner region list type(TAtomList) :: list - !! list of atoms in inner region + !> whole region, low-level class(TCalculator), allocatable :: real_low - !! whole region low level + !> inner region, low-level class(TCalculator), allocatable :: model_low - !! inner region low level + !> inner region, high-level class(TCalculator), allocatable :: model_high - !! inner region high level + !> index list of the inner region integer, allocatable :: idx(:) - !! index list of the inner region + !> topology used for cutting bonds type(TTopology), allocatable :: topo - !! topology used for cutting bonds + !> wavefunctions for inner region calculations type(TRestart) :: chk_low, chk_high - !! wavefunctions for inner region calculations contains @@ -100,31 +99,35 @@ module xtb_oniom contains -!-------------------------------------------------- -! Create ONIOM Calcultor -!-------------------------------------------------- +!> create ONIOM Calcultor subroutine newOniomCalculator(self, env, mol, input) implicit none + + !> new ONIOM calculator type(TOniomCalculator), intent(out) :: self - !! new calculator created in this routine + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(in) :: mol - !! molecular structure data + + !> cml input type(oniom_input), intent(in) :: input - !! CML input - !> Local variables type(TxTBCalculator), allocatable :: xtb type(TOrcaCalculator), allocatable :: orca type(TGFFCalculator), allocatable :: gff integer :: icol integer :: i - !> Method identification + !--------------! + ! method setup ! + !--------------! + + ! methods explicitly specified ! if (allocated(input%first_arg)) then - !! if methods specified icol = index(input%first_arg, ':') if (icol == 0) then @@ -145,15 +148,15 @@ subroutine newOniomCalculator(self, env, mol, input) return end if + ! default, gfn2:gfnff ! else - !! default, gfn2:gfnff self%method_high = 2 self%method_low = 3 endif - !> Write user-defined inner region list into array + ! write user-defined inner region list into array ! self%list = TAtomList(list=input%second_arg) call self%list%to_list(self%idx) @@ -162,22 +165,23 @@ subroutine newOniomCalculator(self, env, mol, input) return end if - !> Check if the user-defined inner region is valid + ! check inner region ! if (any(self%idx < 1) .or. any(self%idx > mol%n)) then call env%error('The specification of inner region is not correct') return end if - !> Whole system calculator allocation + ! whole region calculator ! select case (self%method_low) + + ! gfn1/2 ! case default - !! GFN1/2 allocate (xtb) call newXTBCalculator(env, mol, xtb, method=self%method_low) call move_alloc(xtb, self%real_low) + ! gfnff ! case (3) - !! GFN-FF allocate (gff) call newGFFCalculator(env, mol, gff, "", .false.) call move_alloc(gff, self%real_low) @@ -186,9 +190,7 @@ subroutine newOniomCalculator(self, env, mol, input) end subroutine newOniomCalculator -!--------------------------------------------------------- -! 3 singlepoint energy calculations -!--------------------------------------------------------- +!> 3 singlepoint energy calculations subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradient, sigma, hlgap, results) use xtb_io_writer @@ -196,65 +198,80 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien use xtb_xtb_calculator, only: TxTBCalculator implicit none - !> Dummy-argument list + + !> instance of TOniomCalculator class(TOniomCalculator), intent(inout) :: self - !! instance of TOniomCalculator + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(inout) :: mol - !! molecular structure data + + !> restart data wrapper type(TRestart), intent(inout) :: chk - !! restart data wrapper + + !> print level for IO integer, intent(in) :: printlevel - !! print level for IO + + !> if restarted logical, intent(in) :: restart - !! if restarted + + + !> ONIOM total energy real(wp), intent(out) :: energy - !! ONIOM total energy + + !> ONIOM gradients real(wp), intent(out) :: gradient(:, :) - !! ONIOM gradients + + !> strain derivatives real(wp), intent(out) :: sigma(:, :) - !! strain derivatives + + !> HOMO-LUMO gap real(wp), intent(out) :: hlgap - !! HOMO-LUMO gap + + !> final output stream type(scc_results), intent(out) :: results - !! final output stream - !> Local data - !> Temporary storages + + ! temporary storages ! type(TxTBCalculator), allocatable :: tmp type(TGFFCalculator), allocatable :: gff type(TOrcaCalculator), allocatable :: orca type(TTMCalculator), allocatable :: turbo - !> For inner region high- and low-level calculation + ! for inner region high- and low-level calculation ! type(scc_results) :: results_low, results_high type(TMolecule) :: inner_mol real(wp), allocatable :: gradient_low(:, :), gradient_high(:, :) real(wp) :: energy_model_low, energy_model_high, hlgap_low, hlgap_high real(wp) :: sigma_low(3, 3), sigma_high(3, 3) + !> arrays for matmul of gradient matrix and Jacobian real(wp),allocatable :: arr_gh(:), arr_gl(:) - !! 1-dim arrays for matmul of gradient matrix and Jacobian + + !> Jacobian matrix real(wp), allocatable :: jacobian(:,:) - !! Jacobian matrix + integer,allocatable :: idx2(:) integer :: i, coord_unit logical :: exitRun - !! if any errors occur - !> Check whether the calculator is initialized + ! check whether the calculator is initialized ! if (.not. allocated(self%real_low)) then call env%error("Outer region calculator not provided") return end if - !> Forward solvation to outer region + ! forward solvation to outer region ! if (allocated(self%solvation)) then call move_alloc(self%solvation, self%real_low%solvation) end if - !> First singlepoint of whole system with low-level + !-------------------------! + ! whole system, low-level ! + !-------------------------! + if (.not.set%oniom_settings%cut_inner) then if (printlevel > 0) then @@ -270,12 +287,13 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien endif + ! creating Linked Atoms ! call self%cutbond(env, mol, chk, self%topo, inner_mol,jacobian,idx2) - !! creating Linked Atoms + + ! define inner region charge ! inner_mol%chrg = real(set%oniom_settings%innerchrg) - !! define inner region charge - !> --cut flag termination + ! --cut flag termination ! if (set%oniom_settings%cut_inner) then write(env%unit,'(a)') @@ -293,7 +311,10 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien return end if - !> Inner region, low level method + !-------------------------! + ! inner region, low-level ! + !-------------------------! + if (.not. allocated(self%model_low)) then select case (self%method_low) @@ -301,14 +322,14 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien call env%error("Invalid low-level inner method") return + ! gfn1/2 ! case (1, 2) - !! GFN1/2 allocate (tmp) call newXTBCalculator(env, inner_mol, tmp, method=self%method_low) call move_alloc(tmp, self%model_low) + ! gfnff ! case (3) - !! GFN-FF allocate (gff) call newGFFCalculator(env, inner_mol, gff, "", .false.) call move_alloc(gff, self%model_low) @@ -323,7 +344,10 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien end if - !> Inner region, high-level method + !--------------------------! + ! inner region, high-level ! + !--------------------------! + if (.not. allocated(self%model_high)) then select case (self%method_high) @@ -331,31 +355,33 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien call env%error("Invalid high-level inner method") return + ! gfn1/2 ! case (1, 2) - !! GFN1/2 allocate (tmp) call newXTBCalculator(env, inner_mol, tmp, method=self%method_high) call move_alloc(tmp, self%model_high) + ! gfnff ! case (3) - !! GFN-FF allocate (gff) call newGFFCalculator(env, inner_mol, gff, "", .false.) call move_alloc(gff, self%model_high) + ! orca ! case (4) - !! ORCA allocate (orca) call newOrcaCalculator(orca, env, set%ext_orca,oniom=.true.) call move_alloc(orca, self%model_high) + ! turbomole ! case (5) - !! TURBOMOLE allocate (turbo) call newTMCalculator(turbo, 1, 1) call move_alloc(turbo, self%model_high) + + ! to copy coord file into origin.coord ! call protectCoord(env) - !! to copy coord file into origin.coord + end select call env%check(exitRun) @@ -366,7 +392,7 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien end if - !> To setup partial and shell charges for GFN1/2 + ! setup partial and shell charges for gnf1/2 ! if (.not.allocated(self%chk_low%wfn%qsh)) then select type (calc => self%model_low) type is (TxTBCalculator) @@ -381,7 +407,7 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien end if - !> Inner region low-level method, singlepoint calculation + ! SP: inner region low-level ! if (printlevel > 0) then write(env%unit,'(a)') write(env%unit,'(2x,72("-"))') @@ -398,7 +424,7 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien & energy_model_low, gradient_low, sigma_low, hlgap_low, results_low) - !> Inner region high-level method, singlepoint calculation + ! SP: inner region high-level ! if (printlevel > 0) then write(env%unit,'(a)') write(env%unit,'(2x,72("-"))') @@ -415,7 +441,7 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien & energy_model_high, gradient_high, sigma_high, hlgap_high, results_high) - !> Write opt logs for inner region + ! write opt logs for inner region ! if (set%oniom_settings%logs)then call writeMolecule(inner_mol, set%oniom_settings%ilog1, format=filetype%xyz,energy=energy_model_low) call writeMolecule(inner_mol, set%oniom_settings%ilog2, format=filetype%xyz,energy=energy_model_high) @@ -426,12 +452,15 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien sigma = sigma - sigma_low + sigma_high results%hl_gap = hlgap - hlgap_low + hlgap_high - !> ONIOM energy + !----------------! + ! Postprocessing ! + !----------------! + + ! ONIOM energy ! energy = energy + energy_model_high - energy_model_low results%e_total = energy - !> [gradient*Jacobian] with forward and backward transformation - !! rewrite for hessian + ! [gradient*Jacobian] with forward and backward transformation ! call matrix_to_array(gradient_high,arr_gh) call matrix_to_array(gradient_low,arr_gl) @@ -442,7 +471,7 @@ subroutine singlepoint(self, env, mol, chk, printlevel, restart, energy, gradien call array_to_matrix(arr_gl,gradient_low) - !> ONIOM gradients + ! ONIOM gradients ! do i = 1, size(idx2) gradient(:, idx2(i)) = gradient(:, idx2(i)) + gradient_high(:, i) - gradient_low(:, i) end do @@ -454,22 +483,31 @@ end subroutine singlepoint !> Evaluate hessian by finite difference for all atoms subroutine hessian(self, env, mol0, chk0, list, step, hess, dipgrad) + character(len=*), parameter :: source = "extern_oniom_hessian" - !> Single point calculator + + !> single point calculator class(TOniomCalculator), intent(inout) :: self - !> Computation environment + + !> computation environment type(TEnvironment), intent(inout) :: env - !> Molecular structure data + + !> molecular structure data type(TMolecule), intent(in) :: mol0 - !> Restart data + + !> restart data type(TRestart), intent(in) :: chk0 - !> List of atoms to displace + + !> list of atoms to displace integer, intent(in) :: list(:) - !> Step size for numerical differentiation + + !> step size for numerical differentiation real(wp), intent(in) :: step - !> Array to add Hessian to + + !> array to add Hessian to real(wp), intent(inout) :: hess(:, :) - !> Array to add dipole gradient to + + !> array to add dipole gradient to real(wp), intent(inout) :: dipgrad(:, :) real(wp), allocatable :: jacobian(:,:) @@ -480,12 +518,13 @@ subroutine hessian(self, env, mol0, chk0, list, step, hess, dipgrad) type(TMolecule) :: mol_model integer, allocatable :: list_model(:) - ! Compute complete hessian for outer region + ! compute complete hessian for outer region ! call self%real_low%hessian(env, mol0, chk0, list, step, & & hess, dipgrad) !call chk0%wfn%allocate(mol0%n,chk0%basis%nshell,chk0%real_low%basis%nao) - ! Creating Linked atoms + + ! create linked atoms ! call self%cutbond(env, mol0, chk0, self%topo, mol_model,jacobian,idx2) mol_model%chrg = float(self%chrg_model) list_model = [(ii, ii = 1, size(self%idx))] @@ -534,15 +573,15 @@ subroutine writeInfo(self, unit, mol) class(TOniomCalculator), intent(in) :: self - integer, intent(in) :: unit !> unit for I/O - - type(Tmolecule), intent(in) :: mol !> molecular structural data + !> unit for I/O + integer, intent(in) :: unit + + !> molecular structural data + type(Tmolecule), intent(in) :: mol end subroutine writeInfo -!--------------------------------------------------------------------- -! Create inner region -!--------------------------------------------------------------------- +!> create inner region subroutine cutbond(self, env, mol, chk, topo, inner_mol,jacobian,idx2) use xtb_type_molecule, only: init @@ -553,55 +592,67 @@ subroutine cutbond(self, env, mol, chk, topo, inner_mol,jacobian,idx2) implicit none character(len=*), parameter :: source = "xtb_oniom_cutbond" - !> Dummy-argument list + !> polymorphic calculator class(TOniomCalculator), intent(in) :: self - !! polymorphic calculator + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> wavefunction wrapper type(TRestart), intent(in) :: chk - !! wavefunction wrapper + + !> molecular structure data type(TMolecule), intent(in) :: mol - !! molecular structure data + + !> inner region mol str data type(TMolecule), intent(inout) :: inner_mol - !! inner region + + !> topology info type(TTopology), allocatable, intent(inout) :: topo - !! topology info + + !> jacobian matrix real(wp),allocatable, intent(inout) :: jacobian(:,:) - !! jacobian matrix + + !> list of inner region atom indices + host atoms integer,allocatable, intent(out) :: idx2(:) - !! list of inner region atom indices + host atoms - !> Local variables + !> neighbour list type(TNeighbourList) :: neighList - !! neighbour lists + + !> pair-wise indices for cutbound integer, allocatable :: brokenBondPairs(:,:) - !! pair-wise indices for cutbound + integer, allocatable :: at(:), at2(:) integer, allocatable :: bonded(:, :) real(wp), allocatable :: xyz(:, :), xyz2(:, :) character(len=:),allocatable :: fname_inner + + !> if the both bonded atoms are inside the inner region logical :: inside - !! if the both bonded atoms are inside the inner region + integer :: i, j, n, k, pre_last,iterator integer :: io + !-------! + ! SETUP ! + !-------! inside = .FALSE. + ! initial number of atoms in inner region without LAs ! n = len(self%list) - !! initial number of atoms in inner region without LAs - !> Allocate accordingly the basic molecular data + ! allocate accordingly the basic molecular data ! allocate (at2(size(self%idx))) allocate (xyz2(3, size(self%idx))) allocate (at(n)) allocate (xyz(3, n)) allocate (idx2(size(self%idx))) + ! save inner region list in the matching array ! idx2=self%idx - !! to save inner atom list in the matching array - !> Assign initial inner region + ! assign initial inner region ! do i = 1, size(self%idx) at(i) = mol%at(self%idx(i)) at2(i) = mol%at(self%idx(i)) @@ -609,30 +660,35 @@ subroutine cutbond(self, env, mol, chk, topo, inner_mol,jacobian,idx2) xyz2(:, i) = mol%xyz(:, self%idx(i)) end do + ! initialiaze jacobian as identity ! call create_jacobian(jacobian,at) - !! initialiaze jacobian as identity matrix - !> To identify bonded atoms and save them into an array + assign iterator + ! identify bonded atoms and save them into an array + assign iterator ! select type (calc => self%real_low) class default call env%error("Topology information could not be derived from the given calculator",source) return + ! gfnff ! type is (TGFFCalculator) - !! GFN-FF + + ! bonded atom list ! bonded = calc%topo%blist - !! bonded atom list + + ! number of bonds ! iterator = size(bonded,2) - !! iterator = number of bonds + ! gfn1/2 ! type is (TxTBCalculator) - !! GFN1/2 if (.not. allocated(topo)) then allocate (topo) + + ! return assigned topo%list ! call makeBondTopology(topo, mol, chk%wfn%wbo) - !! return assigned topo%list + + ! return neighList ! call topologyToNeighbourList(topo, neighList, mol) - !! return neighList + end if allocate (bonded(2, len(topo))) @@ -641,110 +697,144 @@ subroutine cutbond(self, env, mol, chk, topo, inner_mol,jacobian,idx2) end do iterator = size(bonded,2) - !! iterator = number of bonds + end select - !> Algorithm to identify broken covalent bonds due to the ONIOM boundary + !-----------! + ! ALGORITHM ! + !-----------! + + ! iterate for all atoms in the user-provided list ! do i = 1, size(self%idx) - !! iterate for all atoms in the user-provided list + + ! iterate through pair of atoms that are bonded ! do j = 1, iterator - !! iterate through pair of atoms that are bonded + + ! if atom in the list is bonded ! if (bonded(1, j) == self%idx(i)) then - !! if atom in the list is bonded + + ! iterate again through the list ! do k = 1, size(self%idx) - !! iterate again through the list + + ! inside inner region ! if (self%idx(k) == bonded(2, j)) then - !! if it is found -> inside inner region inside = .TRUE. end if + end do + ! bond is broken ! if (.not. inside) then - !! if bond is broken - - !> Check if single bond is broken - select type (calc => self%real_low) - class default - call checkfororder(env, mol, self%idx(i), bonded(2, j), bond=topo%list(3, j)) - type is (TGFFCalculator) - call checkfororder(env, mol, self%idx(i), bonded(2, j), hybrid=calc%topo%hyb) - end select - !> Increase no of corresponding arrays by 1 + if (.not.set%oniom_settings%ignore_topo) then + + ! check if single bond is broken ! + select type (calc => self%real_low) + class default + call checkfororder(env, mol, self%idx(i), bonded(2, j), bond=topo%list(3, j)) + type is (TGFFCalculator) + call checkfororder(env, mol, self%idx(i), bonded(2, j), hybrid=calc%topo%hyb) + end select + + endif + + ! increment array size by 1 ! pre_last = size(at) call resize(at) call resize(idx2) + + ! save host atom index ! idx2(pre_last+1) = bonded(2,j) - !! to save index of the host atom + ! assign new atom as H ! at(pre_last + 1) = 1 - !! transform the newly created atom to hydrogen atom(Link Atom) + + + ! adjust coordinate matrix ! call resize(xyz) - !! sdjust accordingly the coordinate matrix + + ! increment Jacobian ! call resize_jacobian(jacobian) - !! increase matrix size in both directions + + ! determine new position of added H atom ! call coord(env,mol,xyz,self%idx(i),bonded(2,j),jacobian,i) - !! determine new position of added H atom end if inside = .FALSE. + + + ! if atom in the list is bonded ! else if (bonded(2, j) == self%idx(i)) then - !! if atom in the list is bonded + + ! iterate again through the list ! do k = 1, size(self%idx) - !! iterate again through the list if (self%idx(k) == bonded(1, j)) then + ! inside inner region ! inside = .TRUE. - !! if it is found -> inside inner region end if end do + + ! bond is broken ! if (.not. inside) then - !! if bond is broken - select type (calc => self%real_low) - !> Check if single bond is broken - class default - call checkfororder(env, mol, self%idx(i), bonded(1, j), bond=topo%list(3, j)) - type is (TGFFCalculator) - call checkfororder(env, mol, self%idx(i), bonded(1, j), hybrid=calc%topo%hyb) - end select + if (.not.set%oniom_settings%ignore_topo) then + + ! check if single bond ! + select type (calc => self%real_low) + class default + call checkfororder(env, mol, self%idx(i), bonded(1, j), bond=topo%list(3, j)) + type is (TGFFCalculator) + call checkfororder(env, mol, self%idx(i), bonded(1, j), hybrid=calc%topo%hyb) + end select - !> Increase no of corresponding arrays by 1 + endif + + ! increment array size by 1 ! pre_last = size(at) call resize(at) call resize(idx2) + + ! save host atom index ! idx2(pre_last+1) = bonded(1,j) - !! to save index of the host atom + ! assign new atom as H ! at(pre_last + 1) = 1 - !! transform the newly created atom to hydrogen atom(Link Atom) + + ! adjust coordinate matrix ! call resize(xyz) - !! adjust accordingly the coordinate matrix + + ! increment Jacobian matrix ! call resize_jacobian(jacobian) - !! increase matrix size in both directions + + ! determine new position of added H atom ! call coord(env,mol, xyz, self%idx(i), bonded(1, j),jacobian,i) - !! determine new position of added H atom + end if inside = .FALSE. + end if end do end do + !----------------! + ! POSTPROCESSING ! + !----------------! + + ! initialize new mol object ! call init(inner_mol, at, xyz) - !! initialize mol object - !> Create Xmol file for inner region + ! create Xmol file for inner region ! if (set%oniom_settings%cut_inner) then fname_inner = "inner_region_without_h.xyz" else fname_inner = "inner_region.xyz" endif + call open_file(io, fname_inner, "w") call writeMolecule(inner_mol, io, filetype%xyz) call close_file(io) end subroutine cutbond -!--------------------------------------- -! increase atomic number array by 1 -!--------------------------------------- +!> increase atomic number array by 1 subroutine new_atom(at) implicit none @@ -758,9 +848,7 @@ subroutine new_atom(at) end subroutine new_atom -!-------------------------------------- -! increase coordinate matrix by 1 -!-------------------------------------- +!> increase coordinate matrix by 1 subroutine new_coordinates(xyz) implicit none @@ -776,9 +864,7 @@ subroutine new_coordinates(xyz) end subroutine new_coordinates -!------------------------------------ -! create identity matrix -!------------------------------------ +!> create identity matrix subroutine create_jacobian(matrix,at) implicit none @@ -799,18 +885,18 @@ subroutine create_jacobian(matrix,at) end subroutine create_jacobian -!---------------------------------------------------- -! To increase matrix dimensionality -! (3 new entries in diagonal and subsequent increase) -!---------------------------------------------------- +!> increase matrix dimensionality +! (3 new entries in diagonal and subsequent increase) ! subroutine resize_jacobian(matrix) implicit none real(wp), allocatable :: matrix(:,:) + + !> temporary storage real(wp), allocatable :: tmp(:,:) - !! To store old values while reallocation + + !> current number of coordinates integer :: coord_num - !! The current number of coordinates coord_num = size(matrix,1) @@ -821,267 +907,296 @@ subroutine resize_jacobian(matrix) end subroutine resize_jacobian -!---------------------------------------------------- -! calculate new postion for LA and corresponding J -!---------------------------------------------------- +!> calculate new postion for LA and corresponding J subroutine newcoord(env,mol,xyz,idx1,idx2,jacobian,connectorPosition) implicit none - !> Dummy-argument list + + !> name of error producer routine character(len=*), parameter :: source = "oniom_newcoord" - !! name of error producer routine + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(in) :: mol - !! molecular structure data + + !> coordinate matrix real(wp), intent(inout) :: xyz(:, :) - !! coordinate matrix + + !> connector (one that stays in the inner region) integer, intent(in) :: idx1 - !! connector, one that stays in the inner region + + !> host (one that is substitued) integer, intent(in) :: idx2 - !! host atom, the one being substitued + + !> jacobian maxtrix real(wp), intent(inout) :: jacobian(:,:) - !! jacobian maxtrix + + !> ordinal number of connector atom in mol%at integer, intent(in) :: connectorPosition - !! ordinal number of connector atom in mol%at - !> Local data + !> standard bond length between LAC(linked atom connector)-H real(wp) :: dist - !! standard bond length between LAC(linked atom connector)-H + + !> standard bond length between LAC(linked atom connector)-LAH(linked atom host) real(wp) :: dist2 - !! standard bond length between LAC(linked atom connector)-LAH(linked atom host) + + !> scaling parameter real(wp) :: prefactor - !! scaling parameter + + !> squared vector length real(wp) :: dist_12 - !! vector length squared + + !> cleaved atom pair coordinates real(wp) :: xyz1(3), xyz2(3) - !! coordinates of the cleaved atom pair + + !> message for default parameter character(len=:), allocatable :: warning - !! message showed in case of default parameter usage + + !> message for auto-switching between derived and fixed modes character(len=:), allocatable :: warning2 - !! message showed in case of the switcing between derived and fixed prefactor values + + !> default is used logical :: def - !! to check if default is used + + !> control warnings logical, save :: rep=.false. - !! to control warnings + + !> ordinal numbers as characters character(len=3) :: dummy1, dummy2 - !! to write ordinal number as character + + !> difference between new and old coordinates real(wp) :: xyz_difference(3) - !! the difference between new and old coordinates + integer :: i,j,k - + + !-------! + ! SETUP ! + !-------! + write (dummy1, '(I3)') mol%at(idx1) write (dummy2, '(I3)') mol%at(idx2) - !> initiale initialization def = .false. warning = "Atoms "//dummy1//" and "//dummy2//" are not accounted in the parameter suite(S,P,N,C,O), the default distance values will be used." warning2 = "The distance between atoms "//dummy1//" and "//dummy2//" is almost the same, switching to fixed regime" + ! coordinates of connector atom ! xyz1 = mol%xyz(:, idx1) - !! coordinates of connector atom + + ! coordinates of host atom ! xyz2 = mol%xyz(:, idx2) - !! coordinates of host atom + dist_12=sum((xyz1 - xyz2)**2) - !! distance squared - !> To identify average bond distances - !> for connector-H and connector-host + ! identify average bond distances ! + ! b/n connector-H and connector-host ! select case (mol%at(idx1)) case default def = .true. + + ! C-H, def ! dist = 1.084*aatoau - !! general case: C-H + ! C-C, def ! dist2 = 1.528*aatoau - !! general case: C-C + ! H ! case (1) - !! H + + ! H-H ! dist = 0.740*aatoau - !! H-H select case (mol%at(idx2)) case default dist2 = 1.084*aatoau def = .true. case(1) + ! H-H ! dist2 = 0.740*aatoau - !! H-H case (6) + ! H-C ! dist2 = 1.084*aatoau - !! H-C case (8) + ! H-O ! dist2 = 0.964*aatoau - !! H-O case (7) + ! H-N ! dist2 = 1.024*aatoau - !! H-N case (15) + ! H-P ! dist2 = 1.414*aatoau - !! H-P case (16) + ! H-S ! dist2 = 1.389*aatoau - !! H-S end select + ! C ! case (6) - !! C + + ! C-H ! dist = 1.084*aatoau - !! C-H select case (mol%at(idx2)) case default dist2 = 1.528*aatoau def = .true. case(1) + ! C-H ! dist2 = 1.084*aatoau - !! C-H case (6) + ! C-C ! dist2 = 1.528*aatoau - !! C-C case (8) + ! C-O ! dist2 = 1.430*aatoau - !! C-O case (7) + ! C-N ! dist2 = 1.475*aatoau - !! C-N case (15) + ! C-P ! dist2 = 1.860*aatoau - !! C-P case (16) + ! C-S ! dist2 = 1.750*aatoau - !! C-S end select + ! N ! case (7) - !! N + + ! N-H ! dist = 1.024*aatoau - !! N-H select case (mol%at(idx2)) case default dist2 = 1.470*aatoau def = .true. case(1) + ! N-H ! dist2 = 1.024*aatoau - !! N-H case (6) + ! N-C ! dist2 = 1.475*aatoau - !! N-C case (8) + ! N-O ! dist2 = 1.360*aatoau - !! N-O case (7) + ! N-N ! dist2 = 1.470*aatoau - !! N-N case (15) + ! N-P ! dist2 = 1.770*aatoau - !! N-P case (16) + ! N-S ! dist2 = 1.650*aatoau - !! N-S end select + ! O ! case (8) - !! O + + ! O-H ! dist = 0.964*aatoau - !! O-H select case (mol%at(idx2)) case default dist2 = 1.450*aatoau def = .true. case(1) + ! O-H ! dist2 = 0.964*aatoau - !! O-H case (6) + ! O-C ! dist2 = 1.430*aatoau - !! O-C case (8) + ! O-O ! dist2 = 1.450*aatoau - !! O-O case (7) + ! O-N ! dist2 = 1.360*aatoau - !! O-N case (15) + ! O-P ! dist2 = 1.750*aatoau - !! O-P case (16) + ! O-S ! dist2 = 1.500*aatoau - !! O-S end select + ! P ! case (15) - !! P + + ! P-H ! dist = 1.414*aatoau - !! P-H select case (mol%at(idx2)) case default dist2 = 1.770*aatoau def = .true. case(1) + ! P-H ! dist2 = 1.414*aatoau - !! P-H case (6) + ! P-C ! dist2 = 1.860*aatoau - !! P-C case (8) + ! P-O ! dist2 = 1.750*aatoau - !! P-O case (7) + ! P-N ! dist2 = 1.770*aatoau - !! P-N endselect + ! S ! case (16) - !! S + + ! S-H ! dist = 1.389*aatoau - !! S-H select case (mol%at(idx2)) case default dist2 = 1.650*aatoau def = .true. case(1) + ! S-H ! dist2 = 1.389*aatoau - !! S-H case (6) + ! S-C ! dist2 = 1.750*aatoau - !! S-C case (8) + ! S-O ! dist2 = 1.500*aatoau - !! S-O case (7) + ! S-N ! dist2 = 1.650*aatoau - !! S-N case (16) + ! S-S ! dist2 = 2.040*aatoau - !! S-S endselect end select - !> different ways of computing scaling parameter prefactor(k) + ! derived mode ! if (set%oniom_settings%derived) then - !! prefactor can change + prefactor = dist/sqrt(dist_12) + + ! fixed mode ! else - !! prefactor is fixed + prefactor = dist/dist2 - !> if default values are used + + ! default values ! if(def.and. .not.rep) then rep=.true. call env%warning(warning,source) endif endif + ! LA coordinates ! xyz(:, size(xyz, 2)) = xyz1 + (xyz2 - xyz1) * prefactor - !! LA (linked atom) coordinates - !> To determine if the difference between the coordinates of LA and LAH is small - !> if yes -> change from derived to fixed + ! determine the difference between LA and LAH cooordinates ! + ! (yes -> change from derived to fixed) ! xyz_difference=xyz2-xyz(:,size(xyz,2)) if (all(xyz_difference<1.0E-5).and.set%oniom_settings%derived) then set%oniom_settings%derived=.false. @@ -1089,42 +1204,54 @@ subroutine newcoord(env,mol,xyz,idx1,idx2,jacobian,connectorPosition) prefactor = dist/dist2 endif + ! take derivatives ! call derivative(jacobian,connectorPosition,size(xyz,2),prefactor,mol%xyz,idx1,idx2,dist_12,set%oniom_settings%derived) - !! take derivatives of model system coordinates wrt whole molecule end subroutine newcoord -!---------------------------------------------------------------------------- -! redefine Jacobian matrix for newly added atoms -!---------------------------------------------------------------------------- +!> increment Jacobian matrix for newly added atoms subroutine derivative(jacobian,con,link,prefactor,xyz,idx1,idx2,dist_12,derived) implicit none - !> Dummy-argument list + + !> jacobian matrix real(wp), intent(inout) :: jacobian(:,:) - !! jacobian matrix + + !> position of connector atom integer,intent(in) :: con - !! position of connector atom in the model system atom list + + !> position of linked atom integer, intent(in) :: link - !! position of linked atom in the model system atom list + + !> scaling factor real(wp),intent(in) :: prefactor - !! scaling factor k + + !> square of distance vector real(wp),intent(in) :: dist_12 - !! square of distance between idx1 and idx2 + + !> coordinates of whole molecule real(wp),intent(in) :: xyz(:,:) - !! coordinates of whole molecule + + !> connector (one that stays in inner region) integer, intent(in) :: idx1 - !! connector, one that stays in the inner region + + !> host (one that is substitued) integer, intent(in) :: idx2 - !! host atom, the one being substitued + + !> fix value of prefactor variable logical, intent(in) :: derived - !! To fix value of prefactor variable + + !> account for all 3 coordinates in J matrix integer :: con3, link3 - !! to account for all 3 coordinates + + !> save the positions of changed matrix elements integer :: counter1(3), counter2(3) - !! to save the positions of changed matrix elements + integer :: i, j + !-------! + ! SETUP ! + !-------! con3=con*3 link3=link*3 @@ -1134,28 +1261,33 @@ subroutine derivative(jacobian,con,link,prefactor,xyz,idx1,idx2,dist_12,derived) counter2(i)=link3-i+1 enddo - !> Assign all new matrix elements to 0 + ! nullify all new matrix elements ! jacobian(counter2(3):,:) = 0.0_wp jacobian(:,counter2(3):) = 0.0_wp - !> Algorithm to find non-zero elements of the matrix + !-------------------------! + ! JACOBIAN INCREMENTATION ! + !-------------------------! + do i=1,3 + ! fixed mode ! if(.not.derived) then - !> Fixed Jacobian jacobian(counter1(i),counter2(i))=1-prefactor jacobian(counter2(i),counter2(i))=prefactor + ! derived mode ! else - !> Derived Jacobian + ! x coordinate ! if (i==1) then - !> x coordinate jacobian(counter2(i),counter2(i)) =(prefactor*( (xyz(2,idx1)**2) - 2*xyz(2,idx1)*xyz(2,idx2) + (xyz(2,idx2)**2) + ((xyz(3,idx1)-xyz(3,idx2))**2) ))/(dist_12**(3.0_wp/2.0_wp)) + + ! y coordinate ! else if (i==2) then - !> y coordinate jacobian(counter2(i),counter2(i)) =(prefactor*( (xyz(1,idx1)**2) - 2*xyz(1,idx1)*xyz(1,idx2) + (xyz(1,idx2)**2) + ((xyz(3,idx1)-xyz(3,idx2))**2) ))/(dist_12**(3.0_wp/2.0_wp)) + + ! z coordinate ! else - !> z coordinate jacobian(counter2(i),counter2(i)) =(prefactor*( (xyz(1,idx1)**2) - 2*xyz(1,idx1)*xyz(1,idx2) + (xyz(1,idx2)**2) + ((xyz(2,idx1)-xyz(2,idx2))**2) ))/(dist_12**(3.0_wp/2.0_wp)) endif @@ -1167,9 +1299,7 @@ subroutine derivative(jacobian,con,link,prefactor,xyz,idx1,idx2,dist_12,derived) end subroutine derivative -!-------------------------------------- -! To allocate method -!-------------------------------------- +!> assign methods function string_to_id(string) result(id) implicit none @@ -1194,29 +1324,32 @@ function string_to_id(string) result(id) end function string_to_id -!---------------------------------------------------------- -! To check if (bond order > 1) -!---------------------------------------------------------- +!> check bond order subroutine checkfororder(env, mol, idx1, idx2, bond, hybrid) implicit none - !> Dummy-argument list - character(len=*), parameter :: source = 'xtb_oniom_checkorder' - !! name of error producer routine + + !> name of error producer routine + character(len=*), parameter :: source = 'xtb_oniom_checkfororder' + + !> hybridization info from GFN-FF; topo%hyb integer, intent(in), optional :: hybrid(:) - !! hybridization from GFN-FF; topo%hyb + + !> wiberg bond orders integer, intent(in), optional :: bond - !! wiberg bond order + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(in) :: mol - !! molecular staructure data + + !> connector (one that stays in inner region) integer, intent(in) :: idx1 - !! connector, one that stays in the inner region + + !> host (one that is substitued) integer, intent(in) :: idx2 - !! host atom, the one being substitued - !> Local data character(len=:), allocatable :: warning integer :: b character(len=5) :: dummy1, dummy2 @@ -1241,27 +1374,29 @@ subroutine checkfororder(env, mol, idx1, idx2, bond, hybrid) end subroutine checkfororder -! ------------------------------------------------- -! Automatic ONIOM inner region charge determination -!-------------------------------------------------- +!> automatic inner region charge determination function calculateCharge(self, env, mol, chk) result(chrg_model) implicit none - !> Dummy-argument list + + !> name of error producer routine character(len=*), parameter :: source = 'xtb_oniom_calculateCharge' - !! name of error producer routine + + !> polymorhic calculator class(TOniomCalculator), intent(inout) :: self - !! polymorhic calculator + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! calculation environment + + !> molecular structure data type(TMolecule), intent(in) :: mol - !! molecular structure data + + !> wavefuntion wrapper type(TRestart), intent(in) :: chk - !! wavefuntion wrapper + + !> inner region charge real(wp) :: charge - !! inner region charge - !> Local data integer :: i, j, n, k, pre_last integer :: chrg_model integer, allocatable :: at(:) @@ -1269,31 +1404,29 @@ function calculateCharge(self, env, mol, chk) result(chrg_model) charge = 0.0_wp select type (calc => self%real_low) + + ! gfnff ! type is (TGFFCalculator) - !! GFN-FF do i = 1, size(self%idx) charge = charge + calc%topo%qa(self%idx(i)) end do + ! GFN1/2 ! type is (TxTBCalculator) - !! GFN1/2 do i = 1, size(self%idx) - charge = charge + chk%wfn%q(self%idx(i)) - + charge = charge + chk%wfn%q(self%idx(i)) end do - class default - call env%error("Not possible to calculate with external methods for real region", source) - return - end select + class default + call env%error("Not possible to calculate with external methods for real region", source) + return + end select - chrg_model = nint(charge) + chrg_model = nint(charge) end function calculateCharge -!--------------------------------------------- -! To transform matrix into 1 dimensional array -!--------------------------------------------- +!> transform matrix into 1-dim array subroutine matrix_to_array(mtrx,arr) implicit none @@ -1313,9 +1446,7 @@ subroutine matrix_to_array(mtrx,arr) end subroutine matrix_to_array -!-------------------------------------------- -! To transform 1 dimensional array to matrix -!-------------------------------------------- +!> transform 1-dim array to matrix subroutine array_to_matrix(arr,mtrx) implicit none @@ -1335,9 +1466,7 @@ subroutine array_to_matrix(arr,mtrx) end subroutine array_to_matrix -!---------------------------------------------------- -! check if the coord is present -> create origin.coord -!---------------------------------------------------- +!> create origin.coord (if coord exist) subroutine protectCoord(env) use xtb_readin, only : mirror_line diff --git a/src/set_module.f90 b/src/set_module.f90 index 01fde19d5..5d777a76e 100644 --- a/src/set_module.f90 +++ b/src/set_module.f90 @@ -810,21 +810,25 @@ subroutine rdcontrol(fname,env,copy_file) maxfrag = maxfrag + ncount !> legacy case('set' ); call rdsetbl(env,set_legacy,line,id,copy,err) + + ! unknown keyword -> ignore, we don't raise them ! + ! except for chrg and spin which you actually can set here ! + ! read them here because select case might not catch them that easy ! case default - !! unknown keyword -> ignore, we don't raise them - !! except for chrg and spin which you actually can set here - !! read them here because select case might not catch them that easy if (index(line(2:),'chrg').eq.1) call set_chrg(env,line(7:)) if (index(line(2:),'spin').eq.1) call set_spin(env,line(7:)) + + ! get a new line ! call mirror_line(id,copy,line,err) - !! get a new line end select + + ! not a keyword -> ignore ! else - !! not a keyword -> ignore call mirror_line(id,copy,line,err) endif + + ! check for end of file (= $end) if (is_iostat_end(err)) exit readflags - !! check for end of file, which I will tolerate as alternative to $end ! if (index(line,flag_end).ne.0) exit readflags ! compatibility reasons call env%check(exitRun) if (exitRun) then @@ -897,25 +901,27 @@ subroutine rdblock(env,handler,line,id,copy,err,ncount) ncount = 0 do call mirror_line(id,copy,line,err) - if (is_iostat_end(err)) return - !! to check if EOF - if (index(line,flag).ne.0) return - !! to check if new flag - ie = index(line,equal) - !! find the equal sign - if (line.eq.'') cycle - !! skip empty lines - ncount = ncount + 1 - !! but count non-empty lines first + + if (is_iostat_end(err)) return ! check if EOF ! + if (index(line,flag).ne.0) return ! check if new flag ! + + ie = index(line,equal) ! find the equal sign ! + if (line.eq.'') cycle ! skip empty lines ! + ncount = ncount + 1 ! but count non-empty lines first ! + if (ie.eq.0) cycle + key = trim(line(:ie-1)) val = trim(adjustl(line(ie+1:))) + call handler(env,key,val) call env%check(exitRun) + if (exitRun) then call env%error("handler could not process input", source) return end if + enddo end subroutine rdblock @@ -926,7 +932,7 @@ subroutine set_exttyp(typ) logical,save :: set1 = .true. if (.not.set1) return select case(typ) - case default ! do nothing + case default ! do nothing ! call raise('S',typ//' is no valid exttyp (internal error)') case('vtb') @@ -964,7 +970,7 @@ subroutine set_geopref(typ) logical,save :: set1 = .true. if (.not.set1) return select case(typ) - case default ! do nothing + case default ! do nothing ! call raise('S',typ//' is no valid geometry format (internal error)') case('sdf') @@ -991,7 +997,7 @@ subroutine set_runtyp(typ) return endif select case(typ) - case default ! do nothing + case default ! do nothing ! call raise('E',typ//' is no valid runtyp (internal error)') case('scc') @@ -1082,18 +1088,20 @@ subroutine set_cut end subroutine set_cut -!----------------------------------- -! Specify charge -!----------------------------------- +!> charge initialization subroutine set_chrg(env,val) implicit none + + !> name of error producer routine character(len=*), parameter :: source = 'set_chrg' - !! Name of error producer routine + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! Calculation environment to handle I/O stream and error log + + !> charge value character(len=*),intent(in) :: val - !! Charge as character + integer :: err integer :: idum integer :: ind, idum1, idum2 @@ -1103,9 +1111,8 @@ subroutine set_chrg(env,val) if (set1) then ind = index(val,":") - + ! inner:outer ! if (ind.ne.0) then - !! inner:outer if (getValue(env,val(:ind-1),idum1) .and. & & getValue(env,val(ind+1:),idum2)) then set%oniom_settings%fixed_chrgs = .true. @@ -1115,10 +1122,11 @@ subroutine set_chrg(env,val) call env%error('Charge could not be read from your argument',source) endif + ! normal single chrg ! else - !! usual case + + ! transform character into int ! if (getValue(env,val,idum)) then - !! to transform character into int set%ichrg = idum else call env%error('Charge could not be read from your argument',source) @@ -1437,22 +1445,25 @@ subroutine set_gfn(env,key,val) end select end subroutine set_gfn -!----------------------------------- -! set ONIOM functionality -!----------------------------------- +!> set ONIOM functionality subroutine set_oniom(env,key,val) implicit none + !> pointer to the error routine character(len=*), parameter :: source = 'set_oniom' - !! pointer to the error routine + + !> calculation environment type(TEnvironment), intent(inout) :: env - !! Calculation environment to handle IO stream and error log + character(len=*), intent(in) :: key + + !> key=val character(len=*), intent(in) :: val - !! key=val + logical :: ldum logical, save :: set1 = .true. logical, save :: set2 = .true. logical, save :: set3 = .true. + logical, save :: set4 = .true. select case(key) case default @@ -1466,9 +1477,12 @@ subroutine set_oniom(env,key,val) set2=.false. case('silent') - if (getValue(env,val,ldum).and.set2) set%oniom_settings%silent = .true. + if (getValue(env,val,ldum).and.set3) set%oniom_settings%silent = .true. set3=.false. + case('ignore topo') + if (getValue(env,val,ldum).and.set4) set%oniom_settings%ignore_topo = .true. + set4=.false. end select end subroutine set_oniom diff --git a/src/setparam.f90 b/src/setparam.f90 index 91f3da29f..433922a11 100644 --- a/src/setparam.f90 +++ b/src/setparam.f90 @@ -102,20 +102,29 @@ module xtb_setparam integer,parameter :: p_pcem_orca = 2 type oniom_settings + !> inner region charge integer :: innerchrg - !! inner region charge + + !> cut high order(>1) covalent bonds + logical :: ignore_topo = .false. + + !> derived mode logical :: derived = .false. - !! set ONIOM optimization parameter g to derived value + + !> dummy execution to check inner region geo and chrg logical :: cut_inner = .false. - !! to execute xtb just for checking inner region cut + + !> explicite charges (inner:outer) logical :: fixed_chrgs= .false. - !! if charges for oniom explicitely given + + !> mute external output (ORCA,TURBOMOLE) logical :: silent = .false. - !! zo mute external output + + !> print optimization logs for inner region calculations logical :: logs = .false. - !! if optimization logs of inner regions are needed + + !> log units integer:: ilog1, ilog2 - !! log units end type oniom_settings type qm_external diff --git a/src/type/timer.f90 b/src/type/timer.f90 index 16c3a4c82..bd64bc37e 100644 --- a/src/type/timer.f90 +++ b/src/type/timer.f90 @@ -23,50 +23,78 @@ module xtb_type_timer private type :: tb_timer + + !> number of timers integer, private :: n = 0 + + !> printlevel logical, private :: verbose = .false. + real(wp),private :: totwall = 0.0_wp real(wp),private :: totcpu = 0.0_wp logical, private,allocatable :: running(:) real(wp),private,allocatable :: twall(:) real(wp),private,allocatable :: tcpu(:) character(len=40),private,allocatable :: tag(:) + contains - procedure :: new => allocate_timer - procedure :: allocate => allocate_timer - procedure :: deallocate => deallocate_timer - procedure :: measure => timer - procedure :: write_timing - procedure :: write => write_all_timings - procedure :: get => get_timer - procedure,private :: start_timing - procedure,private :: stop_timing + + procedure :: new => allocate_timer + procedure :: allocate => allocate_timer + procedure :: deallocate => deallocate_timer + procedure :: measure => timer + procedure :: write_timing + procedure :: write => write_all_timings + procedure :: get => get_timer + procedure,private :: start_timing + procedure,private :: stop_timing + end type tb_timer contains +!> To initialize timer subroutine allocate_timer(self,n,verbose) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> number of timers integer, intent(in) :: n + + !> if verbose logical, intent(in), optional :: verbose + real(wp) :: time_cpu real(wp) :: time_wall + call self%deallocate + + ! capture negative values ! if (n < 1) return - call timing(time_cpu,time_wall) + self%n = n if (present(verbose)) self%verbose = verbose allocate( self%twall(0:n), source = 0.0_wp ) allocate( self%tcpu(0:n), source = 0.0_wp ) allocate( self%running(n), source =.false. ) allocate( self%tag(n) ); self%tag = ' ' + + ! launch timer ! call self%start_timing(0) + end subroutine allocate_timer +!> To deallocate memory subroutine deallocate_timer(self) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + self%n = 0 self%totwall = 0 self%totcpu = 0 @@ -74,40 +102,65 @@ subroutine deallocate_timer(self) if (allocated(self%twall)) deallocate(self%twall) if (allocated(self%tcpu)) deallocate(self%tcpu) if (allocated(self%running)) deallocate(self%running) + end subroutine deallocate_timer +!> To obtain current elapsed time function get_timer(self,i) result(time) + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> if specific timer integer,intent(in),optional :: i + integer :: it real(wp) :: tcpu,twall real(wp) :: time logical :: running + + ! if i is not given, calculate overall elapsed time ! if (present(i)) then it = i else it = 0 endif + if (it > 0) then running = self%running(it) else running = .true. endif + if (running) then call timing(tcpu,twall) time = self%twall(it) + twall else time = self%twall(it) endif + end function get_timer +!> To write timing for specific timer subroutine write_timing(self,iunit,i,inmsg,verbose) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> I/O unit integer,intent(in) :: iunit + + !> index integer,intent(in) :: i - logical,intent(in),optional :: verbose + + !> raw message text character(len=*),intent(in),optional :: inmsg + + !> if verbose + logical,intent(in),optional :: verbose + character(len=26) :: msg real(wp) :: cputime,walltime integer(int64) :: cpudays, cpuhours, cpumins @@ -115,29 +168,48 @@ subroutine write_timing(self,iunit,i,inmsg,verbose) logical :: lverbose ! '(1x,a,1x,"time:",1x,a)' + ! check if tag should be added ! if (present(inmsg)) then msg = inmsg else msg = self%tag(i) endif + + ! verbosity settings ! if (present(verbose)) then lverbose = verbose else lverbose = self%verbose endif + ! DAYS HOURS MINUTES SECONDS ! DAYS 1 1/24 1/1440 1/86400 ! HOURS 24 1 1/60 1/3600 ! MINUTES 1440 60 1 1/60 ! SECONDS 86400 3600 60 1 + + ! convert elapsed CPU time into days, hours, minutes ! cputime = self%tcpu (i) + cpudays = int(cputime/86400._wp) + cputime = cputime - cpudays*86400._wp + cpuhours = int(cputime/3600._wp) + cputime = cputime - cpuhours*3600._wp cpumins = int(cputime/60._wp) cputime = cputime - cpumins*60._wp + ! convert elapsed wall time into days, hours, minutes ! walltime = self%twall(i) + walldays = int(walltime/86400._wp) + walltime = walltime - walldays*86400._wp + wallhours = int(walltime/3600._wp) + walltime = walltime - wallhours*3600._wp wallmins = int(walltime/60._wp) walltime = walltime - wallmins*60._wp + !----------! + ! printout ! + !----------! + if (lverbose) then write(iunit,'(1x,a)') msg write(iunit,'(" * wall-time: ",i5," d, ",i2," h, ",i2," min, ",f6.3," sec")') & @@ -149,13 +221,23 @@ subroutine write_timing(self,iunit,i,inmsg,verbose) write(iunit,'(1x,a30,1x,"...",i9," min, ",f6.3," sec")') & msg, wallmins, walltime endif + end subroutine write_timing +!> To write timing for all timers subroutine write_all_timings(self,iunit,inmsg) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> I/O unit integer,intent(in) :: iunit + + !> raw message character(len=*),intent(in),optional :: inmsg + character(len=26) :: msg real(wp) :: cputime,walltime integer :: i @@ -165,16 +247,20 @@ subroutine write_all_timings(self,iunit,inmsg) call self%stop_timing(0) ! '(1x,a,1x,"time:",1x,a)' + ! check if an external message should be added ! if (present(inmsg)) then msg = inmsg // " (total)" else msg = "total time" endif + ! DAYS HOURS MINUTES SECONDS ! DAYS 1 1/24 1/1440 1/86400 ! HOURS 24 1 1/60 1/3600 ! MINUTES 1440 60 1 1/60 ! SECONDS 86400 3600 60 1 + + ! convert overall elapsed CPU time into days, hours, minutes ! cputime = self%tcpu (0) cpudays = int(cputime/86400._wp) cputime = cputime - cpudays*86400._wp @@ -183,6 +269,7 @@ subroutine write_all_timings(self,iunit,inmsg) cpumins = int(cputime/60._wp) cputime = cputime - cpumins*60._wp + ! convert overall elapsed wall time into days, hours, minutes ! walltime = self%twall(0) walldays = int(walltime/86400._wp) walltime = walltime - walldays*86400._wp @@ -191,6 +278,10 @@ subroutine write_all_timings(self,iunit,inmsg) wallmins = int(walltime/60._wp) walltime = walltime - wallmins*60._wp + !----------! + ! printout ! + !----------! + write(iunit,'(a)') if (self%verbose) then write(iunit,'(1x,a,":")') msg @@ -203,6 +294,8 @@ subroutine write_all_timings(self,iunit,inmsg) write(iunit,'(1x,a26,i5," d, ",i2," h, ",i2," min, ",f6.3," sec")') & msg,walldays,wallhours,wallmins,walltime endif + + ! printout every timer and corresponding speedup ! do i = 1, self%n walltime = self%twall(i) wallmins = int(walltime/60._wp) @@ -211,53 +304,103 @@ subroutine write_all_timings(self,iunit,inmsg) self%tag(i), wallmins, walltime, 100*self%twall(i)/self%twall(0) enddo write(iunit,'(a)') + end subroutine write_all_timings +!> start/stop button subroutine timer(self,i,inmsg) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self - character(len=*),intent(in),optional :: inmsg + + !> index integer,intent(in) :: i + + !> raw message text + character(len=*),intent(in),optional :: inmsg + + + ! check if appropriate index is given ! if (i > self%n .or. i < 1) return + + ! switcher between start/stop status ! if (self%running(i)) then call self%stop_timing(i) else call self%start_timing(i) endif - if (present(inmsg)) self%tag(i) = trim(inmsg) + + ! update status ! self%running(i) = .not.self%running(i) + + ! assign tag to specific timer ! + if (present(inmsg)) self%tag(i) = trim(inmsg) + end subroutine timer +!> To start counting subroutine start_timing(self,i) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> index integer,intent(in) :: i + real(wp) :: time_cpu real(wp) :: time_wall + call timing(time_cpu,time_wall) self%tcpu (i) = self%tcpu (i) - time_cpu self%twall(i) = self%twall(i) - time_wall + end subroutine start_timing +!> To stop counting subroutine stop_timing(self,i) + implicit none + + !> instance of timer class(tb_timer),intent(inout) :: self + + !> index integer,intent(in) :: i + real(wp) :: time_cpu real(wp) :: time_wall + call timing(time_cpu,time_wall) self%tcpu (i) = self%tcpu (i) + time_cpu self%twall(i) = self%twall(i) + time_wall + end subroutine stop_timing +!> To retrieve the current CPU and wall time subroutine timing(time_cpu,time_wall) + implicit none + real(wp),intent(out) :: time_cpu real(wp),intent(out) :: time_wall - integer(int64) :: time_count,time_rate,time_max + + !> current value of system clock (time passed from arbitary point) + integer(int64) :: time_count + + !> number of clock ticks per second (conversion factor b/n ticks and seconds) + integer(int64) :: time_rate + integer(int64) :: time_max + call system_clock(time_count,time_rate,time_max) call cpu_time(time_cpu) + + ! elapsed time in seconds ! time_wall = real(time_count,wp)/real(time_rate,wp) + end subroutine timing end module xtb_type_timer