LCOV - code coverage report
Current view: top level - src/aobasis - ai_moments.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:b310db4) Lines: 97.5 % 200 195
Test Date: 2026-10-23 01:10:43 Functions: 100.0 % 5 5

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Calculation of the moment integrals over Cartesian Gaussian-type
      10              : !>      functions.
      11              : !> \par Literature
      12              : !>      S. Obara and A. Saika, J. Chem. Phys. 84, 3963 (1986)
      13              : !> \par History
      14              : !>      none
      15              : !> \author J. Hutter (16.02.2005)
      16              : ! **************************************************************************************************
      17              : MODULE ai_moments
      18              : 
      19              : ! ax,ay,az  : Angular momentum index numbers of orbital a.
      20              : ! bx,by,bz  : Angular momentum index numbers of orbital b.
      21              : ! coset     : Cartesian orbital set pointer.
      22              : ! dab       : Distance between the atomic centers a and b.
      23              : ! l{a,b}    : Angular momentum quantum number of shell a or b.
      24              : ! l{a,b}_max: Maximum angular momentum quantum number of shell a or b.
      25              : ! l{a,b}_min: Minimum angular momentum quantum number of shell a or b.
      26              : ! rac       : Distance vector between the atomic center a and reference point c.
      27              : ! rbc       : Distance vector between the atomic center b and reference point c.
      28              : ! rpgf{a,b} : Radius of the primitive Gaussian-type function a or b.
      29              : ! zet{a,b}  : Exponents of the Gaussian-type functions a or b.
      30              : ! zetp      : Reciprocal of the sum of the exponents of orbital a and b.
      31              : 
      32              :    USE ai_cartesian_operators, ONLY: apply_cartesian_1d, &
      33              :                                      apply_cartesian_operator, &
      34              :                                      apply_cartesian_operator_pair, &
      35              :                                      cartesian_ladder_map, &
      36              :                                      cartesian_polynomial_1d
      37              :    USE ai_os_rr, ONLY: os_rr_ovlp
      38              :    USE ai_overlap, ONLY: overlap_ab
      39              :    USE kinds, ONLY: dp
      40              :    USE mathconstants, ONLY: pi
      41              :    USE orbital_pointers, ONLY: indco, &
      42              :                                ncoset
      43              : #include "../base/base_uses.f90"
      44              : 
      45              :    IMPLICIT NONE
      46              : 
      47              :    PRIVATE
      48              : 
      49              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ai_moments'
      50              : 
      51              :    PUBLIC :: expikr, moment, diff_momop, contract_expikr, dipole_force
      52              : 
      53              : CONTAINS
      54              : 
      55              : ! **************************************************************************************************
      56              : !> \brief Contract complex primitive integrals into real cosine and sine AO blocks.
      57              : !> \param cos_block ...
      58              : !> \param sin_block ...
      59              : !> \param iatom ...
      60              : !> \param ncoa ...
      61              : !> \param nsgfa ...
      62              : !> \param sgfa ...
      63              : !> \param sphi_a ...
      64              : !> \param ldsa ...
      65              : !> \param jatom ...
      66              : !> \param ncob ...
      67              : !> \param nsgfb ...
      68              : !> \param sgfb ...
      69              : !> \param sphi_b ...
      70              : !> \param ldsb ...
      71              : !> \param expab complex primitive plane-wave integrals
      72              : !> \param work ...
      73              : !> \param ldwork ...
      74              : !> \param ordered retain the ordered atom pair instead of mapping to an upper block
      75              : ! **************************************************************************************************
      76      1539347 :    SUBROUTINE contract_expikr(cos_block, sin_block, &
      77      3078694 :                               iatom, ncoa, nsgfa, sgfa, sphi_a, ldsa, &
      78      3078694 :                               jatom, ncob, nsgfb, sgfb, sphi_b, ldsb, &
      79      1539347 :                               expab, work, ldwork, ordered)
      80              : 
      81              :       REAL(dp), DIMENSION(:, :), POINTER                 :: cos_block, sin_block
      82              :       INTEGER, INTENT(IN)                                :: iatom, ncoa, nsgfa, sgfa
      83              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: sphi_a
      84              :       INTEGER, INTENT(IN)                                :: ldsa, jatom, ncob, nsgfb, sgfb
      85              :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: sphi_b
      86              :       INTEGER, INTENT(IN)                                :: ldsb
      87              :       COMPLEX(dp), DIMENSION(:, :), INTENT(IN)           :: expab
      88              :       REAL(dp), DIMENSION(:, :)                          :: work
      89              :       INTEGER, INTENT(IN)                                :: ldwork
      90              :       LOGICAL, INTENT(IN), OPTIONAL                      :: ordered
      91              : 
      92              :       LOGICAL                                            :: direct_block
      93      1539347 :       REAL(dp), ALLOCATABLE                              :: primitive(:, :)
      94              : 
      95      1539347 :       direct_block = iatom <= jatom
      96      1539347 :       IF (PRESENT(ordered)) direct_block = direct_block .OR. ordered
      97              : 
      98      6157388 :       ALLOCATE (primitive(ncoa, ncob))
      99              :       #:for component in ['cos', 'sin']
     100              :          #:if component == 'cos'
     101    252807510 :             primitive(:, :) = REAL(expab(1:ncoa, 1:ncob), KIND=dp)
     102              :          #:else
     103    252807510 :             primitive(:, :) = AIMAG(expab(1:ncoa, 1:ncob))
     104              :          #:endif
     105              :          CALL dgemm("N", "N", ncoa, nsgfb, ncob, &
     106              :                     1.0_dp, primitive(1, 1), ncoa, &
     107              :                     sphi_b(1, sgfb), ldsb, &
     108      3078694 :                     0.0_dp, work(1, 1), ldwork)
     109              : 
     110      3078694 :          IF (direct_block) THEN
     111              :             CALL dgemm("T", "N", nsgfa, nsgfb, ncoa, &
     112              :                        1.0_dp, sphi_a(1, sgfa), ldsa, &
     113              :                        work(1, 1), ldwork, &
     114              :                        1.0_dp, ${component}$_block(sgfa, sgfb), &
     115      1914320 :                        SIZE(${component}$_block, 1))
     116              :          ELSE
     117              :             CALL dgemm("T", "N", nsgfb, nsgfa, ncoa, &
     118              :                        1.0_dp, work(1, 1), ldwork, &
     119              :                        sphi_a(1, sgfa), ldsa, &
     120              :                        1.0_dp, ${component}$_block(sgfb, sgfa), &
     121      1164374 :                        SIZE(${component}$_block, 1))
     122              :          END IF
     123              :       #:endfor
     124              : 
     125      1539347 :    END SUBROUTINE contract_expikr
     126              : 
     127              : ! **************************************************************************************************
     128              : !> \brief Evaluate primitive exp(i k.r) integrals through the complex overlap recurrence.
     129              : !> \param la_max_set highest bra shell
     130              : !> \param npgfa number of bra primitives
     131              : !> \param zeta bra Gaussian exponents
     132              : !> \param rpgfa bra primitive radii
     133              : !> \param la_min_set lowest bra shell
     134              : !> \param lb_max highest ket shell
     135              : !> \param npgfb number of ket primitives
     136              : !> \param zetb ket Gaussian exponents
     137              : !> \param rpgfb ket primitive radii
     138              : !> \param lb_min lowest ket shell
     139              : !> \param rac bra-center coordinates relative to the phase origin
     140              : !> \param rbc ket-center coordinates relative to the phase origin
     141              : !> \param kvec plane-wave vector
     142              : !> \param expab primitive integrals in the full Cartesian layout, zero below the requested shells
     143              : !> \param dexpab optional bra-center derivatives with the plane-wave operator held fixed
     144              : !> \param dexpba optional ket-center derivatives in the same bra/ket layout
     145              : !> \param momentab optional coordinate-weighted integrals relative to the phase origin
     146              : !>        Derivative and moment outputs cover the full Cartesian range.
     147              : ! **************************************************************************************************
     148      7770705 :    SUBROUTINE expikr(la_max_set, npgfa, zeta, rpgfa, la_min_set, &
     149      1554141 :                      lb_max, npgfb, zetb, rpgfb, lb_min, rac, rbc, kvec, expab, dexpab, dexpba, momentab)
     150              :       INTEGER, INTENT(IN)                                :: la_max_set, npgfa
     151              :       REAL(KIND=dp), INTENT(IN)                          :: zeta(:), rpgfa(:)
     152              :       INTEGER, INTENT(IN)                                :: la_min_set, lb_max, npgfb
     153              :       REAL(KIND=dp), INTENT(IN)                          :: zetb(:), rpgfb(:)
     154              :       INTEGER, INTENT(IN)                                :: lb_min
     155              :       REAL(KIND=dp), INTENT(IN)                          :: rac(3), rbc(3), kvec(3)
     156              :       COMPLEX(KIND=dp), INTENT(INOUT)                    :: expab(:, :)
     157              :       COMPLEX(KIND=dp), INTENT(INOUT), OPTIONAL, TARGET  :: dexpab(:, :, :), dexpba(:, :, :), &
     158              :                                                             momentab(:, :, :)
     159              : 
     160              :       COMPLEX(KIND=dp)                                   :: prefactor, zrap(3), zrbp(3)
     161      1554141 :       COMPLEX(KIND=dp), ALLOCATABLE                      :: opr_rr(:, :, :), rr(:, :, :)
     162      1554141 :       COMPLEX(KIND=dp), POINTER                          :: opr_values(:, :, :)
     163              :       INTEGER                                            :: avec(3), bvec(3), coa, cob, ia, ib, &
     164              :                                                             idir, ipgf, jdir, jpgf, kdir, ldrr, &
     165              :                                                             lma, lmb, ma, mb, na, nb, op
     166              :       LOGICAL                                            :: derivative, right
     167              :       REAL(KIND=dp)                                      :: dab, exponent, f0, f1, f2, k2, kdp, &
     168              :                                                             origin(3), rab(3), rab2, zet, zetp
     169              : 
     170      6216564 :       rab = rbc - rac
     171      6216564 :       dab = NORM2(rab)
     172      6216564 :       rab2 = SUM(rab**2)
     173      6216564 :       k2 = SUM(kvec**2)
     174      1554141 :       lma = la_max_set
     175      1554141 :       lmb = lb_max
     176      1554141 :       IF (PRESENT(dexpab) .OR. PRESENT(momentab)) lma = lma + 1
     177      1554141 :       IF (PRESENT(dexpba)) lmb = lmb + 1
     178      1554141 :       ldrr = MAX(lma, lmb) + 1
     179      7770705 :       ALLOCATE (rr(0:ldrr - 1, 0:ldrr - 1, 3))
     180      1554141 :       IF (PRESENT(dexpab) .OR. PRESENT(dexpba) .OR. PRESENT(momentab)) THEN
     181        71800 :          ALLOCATE (opr_rr(0:la_max_set, 0:lb_max, 3))
     182              :       END IF
     183              : 
     184      1554141 :       na = ncoset(la_max_set)
     185      1554141 :       nb = ncoset(lb_max)
     186    253779848 :       expab(1:na*npgfa, 1:nb*npgfb) = 0.0_dp
     187      4352511 :       IF (PRESENT(dexpab)) dexpab(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
     188      4333107 :       IF (PRESENT(dexpba)) dexpba(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
     189      1641681 :       IF (PRESENT(momentab)) momentab(1:na*npgfa, 1:nb*npgfb, 1:3) = 0.0_dp
     190              : 
     191      5241662 :       DO ipgf = 1, npgfa
     192      3687521 :          ma = (ipgf - 1)*na
     193     17279233 :          DO jpgf = 1, npgfb
     194     12037571 :             IF (rpgfa(ipgf) + rpgfb(jpgf) < dab) CYCLE
     195      4302465 :             mb = (jpgf - 1)*nb
     196      4302465 :             zet = zeta(ipgf) + zetb(jpgf)
     197      4302465 :             zetp = 1.0_dp/zet
     198      4302465 :             f0 = (pi*zetp)**1.5_dp
     199      4302465 :             f1 = zetb(jpgf)*zetp
     200      4302465 :             f2 = 0.5_dp*zetp
     201     17209860 :             kdp = zetp*DOT_PRODUCT(kvec, zeta(ipgf)*rac + zetb(jpgf)*rbc)
     202      4302465 :             prefactor = f0*EXP(CMPLX(-zeta(ipgf)*f1*rab2 - 0.25_dp*k2*zetp, kdp, KIND=dp))
     203              : 
     204              :             ! The normalized 1D tables carry no three-dimensional prefactor.
     205     17209860 :             zrap = CMPLX(f1*rab, f2*kvec, KIND=dp)
     206     17209860 :             zrbp = zrap - rab
     207      4302465 :             CALL os_rr_ovlp(zrap, lma, zrbp, lmb, zet, ldrr, rr)
     208     18511242 :             DO cob = ncoset(lb_min - 1) + 1, nb
     209     56835108 :                bvec = indco(:, cob)
     210     80673102 :                DO coa = ncoset(la_min_set - 1) + 1, na
     211    248647440 :                   avec = indco(:, coa)
     212              :                   expab(ma + coa, mb + cob) = prefactor*rr(avec(1), bvec(1), 1)* &
     213     76370637 :                                               rr(avec(2), bvec(2), 2)*rr(avec(3), bvec(3), 3)
     214              :                END DO
     215              :             END DO
     216              : 
     217     20897381 :             DO op = 1, 3
     218      4302465 :                SELECT CASE (op)
     219              :                CASE (1)
     220      4302465 :                   IF (.NOT. PRESENT(dexpab)) CYCLE
     221        31092 :                   opr_values => dexpab
     222        31092 :                   exponent = zeta(ipgf)
     223              :                CASE (2)
     224      4302465 :                   IF (.NOT. PRESENT(dexpba)) CYCLE
     225        30152 :                   opr_values => dexpba
     226        30152 :                   exponent = zetb(jpgf)
     227              :                CASE (3)
     228      4302465 :                   IF (.NOT. PRESENT(momentab)) CYCLE
     229         4872 :                   opr_values => momentab
     230     12912267 :                   exponent = 0.0_dp
     231              :                END SELECT
     232        66116 :                right = op == 2
     233        66116 :                derivative = op /= 3
     234        66116 :                origin = 0.0_dp
     235        66116 :                IF (.NOT. derivative) origin = rac
     236        66116 :                CALL apply_cartesian_1d(rr, opr_rr, la_max_set, lb_max, right, derivative, exponent, origin)
     237     12258531 :                DO cob = 1, nb
     238       619376 :                   bvec = indco(:, cob)
     239       154844 :                   ib = mb + cob
     240     13530859 :                   DO coa = 1, na
     241      1874480 :                      avec = indco(:, coa)
     242       468620 :                      ia = ma + coa
     243      2029324 :                      DO idir = 1, 3
     244      1405860 :                         jdir = MOD(idir, 3) + 1
     245      1405860 :                         kdir = MOD(idir + 1, 3) + 1
     246              :                         opr_values(ia, ib, idir) = prefactor*opr_rr(avec(idir), bvec(idir), idir)* &
     247      1874480 :                                                    rr(avec(jdir), bvec(jdir), jdir)*rr(avec(kdir), bvec(kdir), kdir)
     248              :                      END DO
     249              :                   END DO
     250              :                END DO
     251              :             END DO
     252              :          END DO
     253              :       END DO
     254      3108282 :    END SUBROUTINE expikr
     255              : 
     256              : ! **************************************************************************************************
     257              : !> \brief ...
     258              : !> \param la_max ...
     259              : !> \param npgfa ...
     260              : !> \param zeta ...
     261              : !> \param rpgfa ...
     262              : !> \param la_min ...
     263              : !> \param lb_max ...
     264              : !> \param npgfb ...
     265              : !> \param zetb ...
     266              : !> \param rpgfb ...
     267              : !> \param lc_max ...
     268              : !> \param rac ...
     269              : !> \param rbc ...
     270              : !> \param mab ...
     271              : !> \param overlap optional zeroth moment in primitive-major cumulative Cartesian order;
     272              : !>        entries outside the requested row and column ranges are untouched
     273              : ! **************************************************************************************************
     274       623512 :    SUBROUTINE moment(la_max, npgfa, zeta, rpgfa, la_min, &
     275      1247024 :                      lb_max, npgfb, zetb, rpgfb, lc_max, rac, rbc, mab, overlap)
     276              :       INTEGER, INTENT(IN)                                :: la_max, npgfa
     277              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zeta, rpgfa
     278              :       INTEGER, INTENT(IN)                                :: la_min, lb_max, npgfb
     279              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zetb, rpgfb
     280              :       INTEGER, INTENT(IN)                                :: lc_max
     281              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: rac, rbc
     282              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: mab
     283              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), OPTIONAL :: overlap
     284              : 
     285              :       INTEGER                                            :: ax, ay, az, bx, by, bz, coa, cob, i, ia, &
     286              :                                                             ib, imom, ipgf, jpgf, ldrr, lx, ly, &
     287       623512 :                                                             lz, ma, mb, powers(0:lc_max)
     288              :       REAL(KIND=dp)                                      :: a, b, dab, f0, rab(3), rab2, rap(3), &
     289              :                                                             rbp(3), zet
     290              :       REAL(KIND=dp), ALLOCATABLE                         :: polynomial(:, :, :, :), rr(:, :, :)
     291              : 
     292              :       MARK_USED(la_min)
     293      2494048 :       rab = rbc - rac
     294      2494048 :       dab = NORM2(rab)
     295       623512 :       rab2 = dab**2
     296       623512 :       ldrr = MAX(la_max + lc_max, lb_max) + 1
     297      6235120 :       ALLOCATE (rr(0:ldrr - 1, 0:ldrr - 1, 3), polynomial(0:la_max, 0:lb_max, 0:lc_max, 3))
     298      4268746 :       powers = [(i, i=0, lc_max)]
     299   2250181978 :       mab(:npgfa*ncoset(la_max), :npgfb*ncoset(lb_max), :ncoset(lc_max) - 1) = 0.0_dp
     300       720778 :       IF (PRESENT(overlap)) overlap(:npgfa*ncoset(la_max), :npgfb*ncoset(lb_max)) = 0.0_dp
     301      2014879 :       DO ipgf = 1, npgfa
     302      1391367 :          ma = (ipgf - 1)*ncoset(la_max)
     303      5762519 :          DO jpgf = 1, npgfb
     304      3747640 :             IF (rpgfa(ipgf) + rpgfb(jpgf) < dab) CYCLE
     305      1449379 :             mb = (jpgf - 1)*ncoset(lb_max)
     306      1449379 :             a = zeta(ipgf)
     307      1449379 :             b = zetb(jpgf)
     308      1449379 :             zet = a + b
     309      5797516 :             rap = b*rab/zet
     310      5797516 :             rbp = -a*rab/zet
     311      1449379 :             f0 = (pi/zet)**1.5_dp*EXP(-a*b*rab2/zet)
     312      1449379 :             CALL os_rr_ovlp(rap, la_max + lc_max, rbp, lb_max, zet, ldrr, rr)
     313      1449379 :             CALL cartesian_polynomial_1d(rr, polynomial, la_max, lb_max, powers, rac)
     314              : 
     315     12979770 :             DO cob = 1, ncoset(lb_max)
     316     10139024 :                bx = indco(1, cob)
     317     10139024 :                by = indco(2, cob)
     318     10139024 :                bz = indco(3, cob)
     319     10139024 :                ib = mb + cob
     320    101068488 :                DO coa = 1, ncoset(la_max)
     321     87181824 :                   ax = indco(1, coa)
     322     87181824 :                   ay = indco(2, coa)
     323     87181824 :                   az = indco(3, coa)
     324     87181824 :                   ia = ma + coa
     325     87181824 :                   IF (PRESENT(overlap)) THEN
     326              :                      overlap(ia, ib) = f0*polynomial(ax, bx, 0, 1)* &
     327        52308 :                                        polynomial(ay, by, 0, 2)*polynomial(az, bz, 0, 3)
     328              :                   END IF
     329              :                   ! Preserve the coset ordering and omission of the zeroth moment.
     330    844498237 :                   DO imom = 1, ncoset(lc_max) - 1
     331    747177389 :                      lx = indco(1, imom + 1)
     332    747177389 :                      ly = indco(2, imom + 1)
     333    747177389 :                      lz = indco(3, imom + 1)
     334              :                      mab(ia, ib, imom) = f0*polynomial(ax, bx, lx, 1)* &
     335    834359213 :                                          polynomial(ay, by, ly, 2)*polynomial(az, bz, lz, 3)
     336              :                   END DO
     337              :                END DO
     338              :             END DO
     339              :          END DO
     340              :       END DO
     341       623512 :    END SUBROUTINE moment
     342              : 
     343              : ! **************************************************************************************************
     344              : !> \brief This returns the derivative of the moment integrals [a|\mu|b].
     345              : !>       By default, it differentiates the primitive on the right:
     346              : !>       [a|\mu|d/dR_bi] =  2*zetb*[a|\mu|b+1i] - Ni(b)[a|\mu|b-1i]
     347              : !>       A weighted derivative combines the left and right primitive derivatives
     348              : !>       using deltaR for the corresponding atom centers.
     349              : !>       order indicates the max order of the moment operator to be calculated
     350              : !>       1: dipole
     351              : !>       2: quadrupole
     352              : !>       ...
     353              : !> \param la_max ...
     354              : !> \param npgfa ...
     355              : !> \param zeta ...
     356              : !> \param rpgfa ...
     357              : !> \param la_min ...
     358              : !> \param lb_max ...
     359              : !> \param npgfb ...
     360              : !> \param zetb ...
     361              : !> \param rpgfb ...
     362              : !> \param lb_min ...
     363              : !> \param order ...
     364              : !> \param rac ...
     365              : !> \param rbc ...
     366              : !> \param difmab ...
     367              : !> \param mab_ext optional precomputed moments with zero screened primitive blocks, including raised shells
     368              : !> \param deltaR optional weights for the left and right primitive derivatives
     369              : !> \param lambda optional atom selector for the factor (iatom == lambda) - (jatom == lambda)
     370              : !> \param iatom atom associated with the left basis function
     371              : !> \param jatom atom associated with the right basis function
     372              : !> \note
     373              : ! **************************************************************************************************
     374       575127 :    SUBROUTINE diff_momop(la_max, npgfa, zeta, rpgfa, la_min, &
     375       575127 :                          lb_max, npgfb, zetb, rpgfb, lb_min, &
     376       575127 :                          order, rac, rbc, difmab, mab_ext, deltaR, lambda, iatom, jatom)
     377              : 
     378              :       INTEGER, INTENT(IN)                                :: la_max, npgfa
     379              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zeta, rpgfa
     380              :       INTEGER, INTENT(IN)                                :: la_min, lb_max, npgfb
     381              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zetb, rpgfb
     382              :       INTEGER, INTENT(IN)                                :: lb_min, order
     383              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: rac, rbc
     384              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(OUT)  :: difmab
     385              :       REAL(KIND=dp), DIMENSION(:, :, :), OPTIONAL, &
     386              :          POINTER                                         :: mab_ext
     387              :       REAL(KIND=dp), DIMENSION(:, :), OPTIONAL, POINTER  :: deltaR
     388              :       INTEGER, INTENT(IN), OPTIONAL                      :: lambda, iatom, jatom
     389              : 
     390              :       INTEGER                                            :: ider, imom, lda, lda_min, ldb, ldb_min
     391              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: difmab_tmp
     392              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: mab
     393              : 
     394       575127 :       lda_min = MAX(0, la_min - 1)
     395       575127 :       ldb_min = MAX(0, lb_min - 1)
     396       575127 :       lda = ncoset(la_max)*npgfa
     397       575127 :       ldb = ncoset(lb_max)*npgfb
     398      2848803 :       ALLOCATE (difmab_tmp(lda, ldb, 3))
     399              : 
     400       575127 :       IF (PRESENT(mab_ext)) THEN
     401       575127 :          mab => mab_ext
     402              :       ELSE
     403              :          ALLOCATE (mab(npgfa*ncoset(la_max + 1), npgfb*ncoset(lb_max + 1), &
     404            0 :                        ncoset(order) - 1))
     405            0 :          mab = 0.0_dp
     406              : !     *** Calculate the primitive overlap integrals ***
     407              :          CALL moment(la_max + 1, npgfa, zeta, rpgfa, lda_min, &
     408              :                      lb_max + 1, npgfb, zetb, rpgfb, &
     409            0 :                      order, rac, rbc, mab)
     410              : 
     411              :       END IF
     412      5731812 :       DO imom = 1, ncoset(order) - 1
     413              :          CALL apply_cartesian_operator(la_max, 0, npgfa, lb_max, 0, npgfb, mab(:, :, imom), &
     414      5156685 :                                        difmab_tmp, right=.TRUE., derivative=.TRUE., exponents=zetb)
     415      5731812 :          IF (PRESENT(deltaR)) THEN
     416         6804 :             CPASSERT(ASSOCIATED(deltaR))
     417         6804 :             CPASSERT(PRESENT(iatom) .AND. PRESENT(jatom))
     418        27216 :             DO ider = 1, 3
     419              :                difmab(1:lda, 1:ldb, imom, ider) = &
     420      1496880 :                   difmab_tmp(1:lda, 1:ldb, ider)*deltaR(ider, jatom)
     421              :             END DO
     422              : 
     423              :             CALL apply_cartesian_operator(la_max, 0, npgfa, lb_max, 0, npgfb, mab(:, :, imom), &
     424         6804 :                                           difmab_tmp, right=.FALSE., derivative=.TRUE., exponents=zeta)
     425        27216 :             DO ider = 1, 3
     426              :                difmab(1:lda, 1:ldb, imom, ider) = difmab(1:lda, 1:ldb, imom, ider) &
     427      1496880 :                                                   + difmab_tmp(1:lda, 1:ldb, ider)*deltaR(ider, iatom)
     428              :             END DO
     429              :          ELSE
     430   1124774136 :             difmab(1:lda, 1:ldb, imom, :) = difmab_tmp(1:lda, 1:ldb, :)
     431              :          END IF
     432              :       END DO
     433              : 
     434       575127 :       IF (PRESENT(lambda)) THEN
     435           27 :          CPASSERT(.NOT. PRESENT(deltaR))
     436           27 :          CPASSERT(PRESENT(iatom) .AND. PRESENT(jatom))
     437           27 :          IF (iatom == lambda .AND. jatom == lambda) THEN
     438         7383 :             difmab = 0.0_dp
     439           24 :          ELSE IF (iatom == lambda) THEN
     440              :             ! The right-hand derivative is selected with a positive sign.
     441           18 :          ELSE IF (jatom == lambda) THEN
     442        14766 :             difmab = -difmab
     443              :          ELSE
     444        29532 :             difmab = 0.0_dp
     445              :          END IF
     446              :       END IF
     447              : 
     448       575127 :       IF (PRESENT(mab_ext)) THEN
     449              :          NULLIFY (mab)
     450              :       ELSE
     451            0 :          DEALLOCATE (mab)
     452              :       END IF
     453       575127 :       DEALLOCATE (difmab_tmp)
     454              : 
     455       575127 :    END SUBROUTINE diff_momop
     456              : 
     457              : ! **************************************************************************************************
     458              : !> \brief This returns the derivative of the dipole integrals [a|x|b], with respect
     459              : !>       to the position of the primitive on the left and right, i.e.
     460              : !>       [da/dR_ai|\mu|b] =  2*zeta*[a+1i|\mu|b] - Ni(a)[a-1i|\mu|b]
     461              : !> \param la_max ...
     462              : !> \param npgfa ...
     463              : !> \param zeta ...
     464              : !> \param rpgfa ...
     465              : !> \param la_min ...
     466              : !> \param lb_max ...
     467              : !> \param npgfb ...
     468              : !> \param zetb ...
     469              : !> \param rpgfb ...
     470              : !> \param lb_min ...
     471              : !> \param order ...
     472              : !> \param rac ...
     473              : !> \param rbc ...
     474              : !> \param pab ...
     475              : !> \param forcea ...
     476              : !> \param forceb ...
     477              : !> \note
     478              : ! **************************************************************************************************
     479         2100 :    SUBROUTINE dipole_force(la_max, npgfa, zeta, rpgfa, la_min, &
     480         2100 :                            lb_max, npgfb, zetb, rpgfb, lb_min, &
     481         2100 :                            order, rac, rbc, pab, forcea, forceb)
     482              : 
     483              :       INTEGER, INTENT(IN)                                :: la_max, npgfa
     484              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zeta, rpgfa
     485              :       INTEGER, INTENT(IN)                                :: la_min, lb_max, npgfb
     486              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: zetb, rpgfb
     487              :       INTEGER, INTENT(IN)                                :: lb_min, order
     488              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: rac, rbc
     489              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: pab
     490              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), TARGET :: forcea, forceb
     491              : 
     492              :       INTEGER, PARAMETER :: components(2, 9) = RESHAPE([1, 1, 2, 1, 3, 1, 1, 2, 2, 2, 3, 2, 1, 3, 2, 3, 3, 3], [2, 9])
     493              :       INTEGER :: axis, first_a, first_b, icomp, ipgf, jpgf, ma, mb, nrow, ncol, side
     494         4200 :       INTEGER :: map_a(4, ncoset(la_max) - ncoset(la_min - 1), 3), &
     495         4200 :                  map_b(4, ncoset(lb_max) - ncoset(lb_min - 1), 3)
     496         4200 :       REAL(KIND=dp) :: origin(3, 2), rab(3), distance, rr_work(3*(MAX(la_max, lb_max) + 2)**2)
     497         2100 :       REAL(KIND=dp), ALLOCATABLE :: source(:, :), work(:, :), derivatives(:, :, :)
     498         2100 :       REAL(KIND=dp), POINTER :: forces(:, :)
     499              : 
     500            0 :       CPASSERT(order == 1)
     501              :       MARK_USED(order)
     502         2100 :       first_a = ncoset(la_min - 1) + 1
     503         2100 :       first_b = ncoset(lb_min - 1) + 1
     504         2100 :       nrow = ncoset(la_max) - first_a + 1
     505         2100 :       ncol = ncoset(lb_max) - first_b + 1
     506              :       ALLOCATE (source(ncoset(la_max + 1), ncoset(lb_max + 1)), work(ncoset(la_max + 1), ncoset(lb_max + 1)), &
     507        21000 :                 derivatives(nrow, ncol, 9))
     508         8400 :       DO axis = 1, 3
     509         6300 :          CALL cartesian_ladder_map(la_max, la_min, axis, map_a(:, :, axis), source_lmin=0)
     510         8400 :          CALL cartesian_ladder_map(lb_max, lb_min, axis, map_b(:, :, axis), source_lmin=0)
     511              :       END DO
     512         2100 :       origin = 0.0_dp
     513         8400 :       rab = rbc - rac
     514         8400 :       distance = NORM2(rab)
     515         8036 :       DO ipgf = 1, npgfa
     516         5936 :          ma = (ipgf - 1)*ncoset(la_max)
     517        25033 :          DO jpgf = 1, npgfb
     518        16997 :             IF (rpgfa(ipgf) + rpgfb(jpgf) < distance) CYCLE
     519        13411 :             mb = (jpgf - 1)*ncoset(lb_max)
     520              :             CALL overlap_ab(la_max + 1, 0, 1, rpgfa(ipgf:ipgf), zeta(ipgf:ipgf), &
     521              :                             lb_max + 1, 0, 1, rpgfb(jpgf:jpgf), zetb(jpgf:jpgf), rab, &
     522        13411 :                             sab=source, rr_work=rr_work)
     523              :             ! Multiply by the coordinate on the side opposite the differentiated Gaussian.
     524        46169 :             DO side = 1, 2
     525        26822 :                IF (side == 1) THEN
     526        13411 :                   forces => forcea
     527        53644 :                   origin(:, 1) = rbc
     528              :                   CALL apply_cartesian_operator_pair(source, derivatives, map_b, map_a, components, &
     529              :                                                      [.FALSE., .TRUE.], [0.0_dp, zeta(ipgf)], &
     530        40233 :                                                      [.TRUE., .FALSE.], work(:, 1:ncol), origin)
     531              :                ELSE
     532        13411 :                   forces => forceb
     533        53644 :                   origin(:, 1) = rac
     534              :                   CALL apply_cartesian_operator_pair(source, derivatives, map_a, map_b, components, &
     535              :                                                      [.FALSE., .TRUE.], [0.0_dp, zetb(jpgf)], &
     536        40233 :                                                      [.FALSE., .TRUE.], work(1:nrow, :), origin)
     537              :                END IF
     538       285217 :                DO icomp = 1, 9
     539              :                   forces(components(1, icomp), components(2, icomp)) = &
     540              :                      forces(components(1, icomp), components(2, icomp)) + &
     541      2577998 :                      SUM(pab(ma + first_a:ma + ncoset(la_max), mb + first_b:mb + ncoset(lb_max))*derivatives(:, :, icomp))
     542              :                END DO
     543              :             END DO
     544              :          END DO
     545              :       END DO
     546              : 
     547         4200 :    END SUBROUTINE dipole_force
     548              : 
     549              : END MODULE ai_moments
        

Generated by: LCOV version 2.0-1