LCOV - code coverage report
Current view: top level - src - pao_linpot_rotinv.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 98.5 % 259 255
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 3 3

            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 Rotationally invariant parametrization of Fock matrix.
      10              : !> \author Ole Schuett
      11              : ! **************************************************************************************************
      12              : MODULE pao_linpot_rotinv
      13              :    USE ai_overlap,                      ONLY: overlap_aab
      14              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      15              :    USE basis_set_types,                 ONLY: gto_basis_set_type
      16              :    USE cell_types,                      ONLY: cell_type,&
      17              :                                               pbc
      18              :    USE kinds,                           ONLY: dp
      19              :    USE mathconstants,                   ONLY: gamma1
      20              :    USE mathlib,                         ONLY: multinomial
      21              :    USE orbital_pointers,                ONLY: indco,&
      22              :                                               ncoset
      23              :    USE particle_types,                  ONLY: particle_type
      24              :    USE qs_environment_types,            ONLY: get_qs_env,&
      25              :                                               qs_environment_type
      26              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      27              :                                               pao_potential_type,&
      28              :                                               qs_kind_type
      29              : #include "./base/base_uses.f90"
      30              : 
      31              :    IMPLICIT NONE
      32              : 
      33              :    PRIVATE
      34              : 
      35              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_linpot_rotinv'
      36              : 
      37              :    PUBLIC :: linpot_rotinv_count_terms, linpot_rotinv_calc_terms, linpot_rotinv_calc_forces
      38              : 
      39              : CONTAINS
      40              : 
      41              : ! **************************************************************************************************
      42              : !> \brief Count number of terms for given atomic kind
      43              : !> \param qs_env ...
      44              : !> \param ikind ...
      45              : !> \param nterms ...
      46              : ! **************************************************************************************************
      47          538 :    SUBROUTINE linpot_rotinv_count_terms(qs_env, ikind, nterms)
      48              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      49              :       INTEGER, INTENT(IN)                                :: ikind
      50              :       INTEGER, INTENT(OUT)                               :: nterms
      51              : 
      52              :       CHARACTER(len=*), PARAMETER :: routineN = 'linpot_rotinv_count_terms'
      53              : 
      54              :       INTEGER                                            :: handle, ipot, iset, ishell, ishell_abs, &
      55              :                                                             lmax, lmin, lpot, max_shell, &
      56              :                                                             min_shell, npots, nshells, pot_maxl
      57          538 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: shell_l
      58              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
      59          538 :       TYPE(pao_potential_type), DIMENSION(:), POINTER    :: pao_potentials
      60          538 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      61              : 
      62          538 :       CALL timeset(routineN, handle)
      63              : 
      64          538 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
      65          538 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, pao_potentials=pao_potentials)
      66              : 
      67         1132 :       nshells = SUM(basis_set%nshell)
      68          538 :       npots = SIZE(pao_potentials)
      69              : 
      70          538 :       CPWARN_IF(npots == 0, "Found no PAO_POTENTIAL section")
      71              : 
      72              :       ! fill shell_l
      73         1614 :       ALLOCATE (shell_l(nshells))
      74         1132 :       DO iset = 1, basis_set%nset
      75         2832 :       DO ishell = 1, basis_set%nshell(iset)
      76         1756 :          ishell_abs = SUM(basis_set%nshell(1:iset - 1)) + ishell
      77         2294 :          shell_l(ishell_abs) = basis_set%l(ishell, iset)
      78              :       END DO
      79              :       END DO
      80              : 
      81          538 :       nterms = 0
      82              : 
      83              :       ! terms sensing neighboring atoms
      84         1081 :       DO ipot = 1, npots
      85          543 :          pot_maxl = pao_potentials(ipot)%maxl ! maxl is taken from central atom
      86          543 :          IF (pot_maxl < 0) THEN
      87            0 :             CPABORT("ROTINV parametrization requires non-negative PAO_POTENTIAL%MAXL")
      88              :          END IF
      89          543 :          IF (MOD(pot_maxl, 2) /= 0) THEN
      90            0 :             CPABORT("ROTINV parametrization requires even-numbered PAO_POTENTIAL%MAXL")
      91              :          END IF
      92         2796 :          DO max_shell = 1, nshells
      93         5875 :          DO min_shell = 1, max_shell
      94         9903 :          DO lpot = 0, pot_maxl, 2
      95         4571 :             lmin = shell_l(min_shell)
      96         4571 :             lmax = shell_l(max_shell)
      97         4571 :             IF (lmin == 0 .AND. lmax == 0) CYCLE ! covered by central terms
      98         8188 :             nterms = nterms + 1
      99              :          END DO
     100              :          END DO
     101              :          END DO
     102              :       END DO
     103              : 
     104              :       ! spherical symmetric terms on central atom
     105         2238 :       DO max_shell = 1, nshells
     106         5825 :       DO min_shell = 1, max_shell
     107         3587 :          IF (shell_l(min_shell) /= shell_l(max_shell)) CYCLE ! need quadratic block
     108         5287 :          nterms = nterms + 1
     109              :       END DO
     110              :       END DO
     111              : 
     112          538 :       CALL timestop(handle)
     113              : 
     114         1076 :    END SUBROUTINE linpot_rotinv_count_terms
     115              : 
     116              : ! **************************************************************************************************
     117              : !> \brief Calculate all potential terms of the rotinv parametrization
     118              : !> \param qs_env ...
     119              : !> \param iatom ...
     120              : !> \param V_blocks ...
     121              : ! **************************************************************************************************
     122          195 :    SUBROUTINE linpot_rotinv_calc_terms(qs_env, iatom, V_blocks)
     123              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     124              :       INTEGER, INTENT(IN)                                :: iatom
     125              :       REAL(dp), DIMENSION(:, :, :), INTENT(OUT), TARGET  :: V_blocks
     126              : 
     127              :       CHARACTER(len=*), PARAMETER :: routineN = 'linpot_rotinv_calc_terms'
     128              : 
     129              :       INTEGER :: handle, i, ic, ikind, ipot, iset, ishell, ishell_abs, jatom, jkind, jset, jshell, &
     130              :          jshell_abs, kterm, la1_max, la1_min, la2_max, la2_min, lb_max, lb_min, lpot, N, na1, na2, &
     131              :          natoms, nb, ncfga1, ncfga2, ncfgb, npgfa1, npgfa2, npgfb, npots, pot_maxl, sgfa1, sgfa2, &
     132              :          sgla1, sgla2
     133              :       REAL(dp)                                           :: coeff, norm2, pot_beta, pot_weight, &
     134              :                                                             rpgfa_max, tab
     135              :       REAL(dp), DIMENSION(3)                             :: Ra, Rab, Rb
     136          195 :       REAL(dp), DIMENSION(:), POINTER                    :: rpgfa1, rpgfa2, rpgfb, zeta1, zeta2, zetb
     137          195 :       REAL(dp), DIMENSION(:, :), POINTER                 :: T1, T2, V12, V21
     138          195 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: block_V_full, saab, saal
     139              :       TYPE(cell_type), POINTER                           :: cell
     140              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     141          195 :       TYPE(pao_potential_type), DIMENSION(:), POINTER    :: ipao_potentials, jpao_potentials
     142          195 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     143          195 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     144              : 
     145          195 :       CALL timeset(routineN, handle)
     146              : 
     147              :       CALL get_qs_env(qs_env, &
     148              :                       natom=natoms, &
     149              :                       cell=cell, &
     150              :                       particle_set=particle_set, &
     151          195 :                       qs_kind_set=qs_kind_set)
     152              : 
     153          195 :       CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     154          195 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, pao_potentials=ipao_potentials)
     155          195 :       npots = SIZE(ipao_potentials)
     156          195 :       N = basis_set%nsgf ! primary basis-size
     157          195 :       CPASSERT(SIZE(V_blocks, 1) == N .AND. SIZE(V_blocks, 2) == N)
     158          195 :       kterm = 0 ! init counter
     159              : 
     160          391 :       DO ipot = 1, npots
     161          196 :          pot_maxl = ipao_potentials(ipot)%maxl ! taken from central atom
     162              : 
     163              :          ! setup description of potential
     164          196 :          lb_min = 0
     165          196 :          lb_max = pot_maxl
     166          196 :          ncfgb = ncoset(lb_max) - ncoset(lb_min - 1)
     167          196 :          npgfb = 1 ! number of exponents
     168          196 :          nb = npgfb*ncfgb
     169          196 :          ALLOCATE (rpgfb(npgfb), zetb(npgfb))
     170              : 
     171              :          ! build block_V_full
     172          980 :          ALLOCATE (block_V_full(N, N, pot_maxl/2 + 1))
     173         8116 :          block_V_full = 0.0_dp
     174              : 
     175          418 :          DO iset = 1, basis_set%nset
     176          666 :          DO jset = 1, iset
     177              : 
     178              :             ! setup iset
     179          248 :             la1_max = basis_set%lmax(iset)
     180          248 :             la1_min = basis_set%lmin(iset)
     181          248 :             npgfa1 = basis_set%npgf(iset)
     182          248 :             ncfga1 = ncoset(la1_max) - ncoset(la1_min - 1)
     183          248 :             na1 = npgfa1*ncfga1
     184          248 :             zeta1 => basis_set%zet(:, iset)
     185          248 :             rpgfa1 => basis_set%pgf_radius(:, iset)
     186              : 
     187              :             ! setup jset
     188          248 :             la2_max = basis_set%lmax(jset)
     189          248 :             la2_min = basis_set%lmin(jset)
     190          248 :             npgfa2 = basis_set%npgf(jset)
     191          248 :             ncfga2 = ncoset(la2_max) - ncoset(la2_min - 1)
     192          248 :             na2 = npgfa2*ncfga2
     193          248 :             zeta2 => basis_set%zet(:, jset)
     194          248 :             rpgfa2 => basis_set%pgf_radius(:, jset)
     195              : 
     196              :             ! radius of most diffuse basis-function
     197         3296 :             rpgfa_max = MAX(MAXVAL(rpgfa1), MAXVAL(rpgfa2))
     198              : 
     199              :             ! allocate space for integrals
     200         2232 :             ALLOCATE (saab(na1, na2, nb), saal(na1, na2, pot_maxl/2 + 1))
     201       150372 :             saal = 0.0_dp
     202              : 
     203              :             ! loop over neighbors
     204          754 :             DO jatom = 1, natoms
     205          506 :                IF (jatom == iatom) CYCLE ! no self-interaction
     206          258 :                CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
     207          258 :                CALL get_qs_kind(qs_kind_set(jkind), pao_potentials=jpao_potentials)
     208          258 :                IF (SIZE(jpao_potentials) /= npots) THEN
     209            0 :                   CPABORT("Not all KINDs have the same number of PAO_POTENTIAL sections")
     210              :                END IF
     211              : 
     212              :                ! initialize exponents
     213          258 :                pot_weight = jpao_potentials(ipot)%weight ! taken from remote atom
     214          258 :                pot_beta = jpao_potentials(ipot)%beta ! taken from remote atom
     215          258 :                rpgfb(1) = jpao_potentials(ipot)%beta_radius ! taken from remote atom
     216          258 :                zetb(1) = pot_beta
     217              : 
     218              :                ! calculate direction
     219         1032 :                Ra = particle_set(iatom)%r
     220         1032 :                Rb = particle_set(jatom)%r
     221          258 :                Rab = pbc(ra, rb, cell)
     222              : 
     223              :                ! distance screening
     224         1032 :                tab = SQRT(SUM(Rab**2))
     225          258 :                IF (rpgfa_max + rpgfb(1) < tab) CYCLE
     226              : 
     227              :                ! calculate actual integrals
     228       689244 :                saab = 0.0_dp
     229              :                CALL overlap_aab(la1_max=la1_max, la1_min=la1_min, npgfa1=npgfa1, rpgfa1=rpgfa1, zeta1=zeta1, &
     230              :                                 la2_max=la2_max, la2_min=la2_min, npgfa2=npgfa2, rpgfa2=rpgfa2, zeta2=zeta2, &
     231              :                                 lb_max=lb_max, lb_min=lb_min, npgfb=npgfb, rpgfb=rpgfb, zetb=zetb, &
     232          258 :                                 rab=Rab, saab=saab)
     233              : 
     234              :                ! sum neighbor contributions according to remote atom's weight and normalization
     235         1058 :                DO lpot = 0, pot_maxl, 2
     236          294 :                   norm2 = (2.0_dp*pot_beta)**(-0.5_dp - lpot)*gamma1(lpot)
     237              :                   ! sum potential terms: POW(x**2 + y**2 + z**2, lpot/2)
     238         1436 :                   DO ic = ncoset(lpot - 1) + 1, ncoset(lpot)
     239         2544 :                      coeff = multinomial(lpot/2, indco(:, ic)/2)
     240       959082 :                      saal(:, :, lpot/2 + 1) = saal(:, :, lpot/2 + 1) + saab(:, :, ic)*coeff*pot_weight/SQRT(norm2)
     241              :                   END DO
     242              :                END DO
     243              :             END DO ! jatom
     244              : 
     245              :             ! find bounds of set-pair and setup transformation matrices
     246          248 :             sgfa1 = basis_set%first_sgf(1, iset)
     247          248 :             sgla1 = sgfa1 + basis_set%nsgf_set(iset) - 1
     248          248 :             sgfa2 = basis_set%first_sgf(1, jset)
     249          248 :             sgla2 = sgfa2 + basis_set%nsgf_set(jset) - 1
     250          248 :             T1 => basis_set%scon(1:na1, sgfa1:sgla1)
     251          248 :             T2 => basis_set%scon(1:na2, sgfa2:sgla2)
     252              : 
     253              :             ! transform into primary basis
     254          248 :             DO lpot = 0, pot_maxl, 2
     255          268 :                V12 => block_V_full(sgfa1:sgla1, sgfa2:sgla2, lpot/2 + 1)
     256          268 :                V21 => block_V_full(sgfa2:sgla2, sgfa1:sgla1, lpot/2 + 1)
     257      1735432 :                V12 = MATMUL(TRANSPOSE(T1), MATMUL(saal(:, :, lpot/2 + 1), T2))
     258        15364 :                V21 = TRANSPOSE(V12)
     259              :             END DO
     260          470 :             DEALLOCATE (saab, saal)
     261              :          END DO ! jset
     262              :          END DO ! iset
     263          196 :          DEALLOCATE (rpgfb, zetb)
     264              : 
     265              :          ! block_V_full is ready -------------------------------------------------------------------
     266              :          ! split the full blocks into shell-pair sub-blocks
     267          418 :          DO iset = 1, basis_set%nset
     268          666 :          DO jset = 1, iset
     269         1114 :          DO ishell = 1, basis_set%nshell(iset)
     270         2792 :          DO jshell = 1, basis_set%nshell(jset)
     271         1900 :             IF (basis_set%l(ishell, iset) == 0 .AND. basis_set%l(jshell, jset) == 0) CYCLE ! covered by central terms
     272         1090 :             ishell_abs = SUM(basis_set%nshell(1:iset - 1)) + ishell
     273         1012 :             jshell_abs = SUM(basis_set%nshell(1:jset - 1)) + jshell
     274          986 :             IF (ishell_abs < jshell_abs) CYCLE
     275              : 
     276              :             ! find bounds of shell-pair
     277          632 :             sgfa1 = basis_set%first_sgf(ishell, iset)
     278          632 :             sgla1 = basis_set%last_sgf(ishell, iset)
     279          632 :             sgfa2 = basis_set%first_sgf(jshell, jset)
     280          632 :             sgla2 = basis_set%last_sgf(jshell, jset)
     281              : 
     282         1276 :             DO lpot = 0, pot_maxl, 2
     283          728 :                kterm = kterm + 1
     284        34760 :                V_blocks(:, :, kterm) = 0.0_dp
     285        10896 :                V_blocks(sgfa1:sgla1, sgfa2:sgla2, kterm) = block_V_full(sgfa1:sgla1, sgfa2:sgla2, lpot/2 + 1)
     286        14188 :                V_blocks(sgfa2:sgla2, sgfa1:sgla1, kterm) = block_V_full(sgfa2:sgla2, sgfa1:sgla1, lpot/2 + 1)
     287              :             END DO ! lpot
     288              :          END DO ! jshell
     289              :          END DO ! ishell
     290              :          END DO ! jset
     291              :          END DO ! iset
     292          391 :          DEALLOCATE (block_V_full)
     293              :       END DO ! ipot
     294              : 
     295              :       ! terms on central atom ----------------------------------------------------------------------
     296              : 
     297          416 :       DO iset = 1, basis_set%nset
     298          663 :       DO jset = 1, iset
     299         1109 :       DO ishell = 1, basis_set%nshell(iset)
     300         2779 :       DO jshell = 1, basis_set%nshell(jset)
     301         1891 :          IF (basis_set%l(ishell, iset) /= basis_set%l(jshell, jset)) CYCLE ! need quadratic block
     302         1139 :          ishell_abs = SUM(basis_set%nshell(1:iset - 1)) + ishell
     303         1139 :          jshell_abs = SUM(basis_set%nshell(1:jset - 1)) + jshell
     304         1113 :          IF (ishell_abs < jshell_abs) CYCLE
     305          864 :          kterm = kterm + 1
     306          864 :          sgfa1 = basis_set%first_sgf(ishell, iset)
     307          864 :          sgla1 = basis_set%last_sgf(ishell, iset)
     308          864 :          sgfa2 = basis_set%first_sgf(jshell, jset)
     309          864 :          sgla2 = basis_set%last_sgf(jshell, jset)
     310          864 :          CPASSERT((sgla1 - sgfa1) == (sgla2 - sgfa2)) ! should be a quadratic block
     311        31096 :          V_blocks(:, :, kterm) = 0.0_dp
     312         2134 :          DO i = 1, sgla1 - sgfa1 + 1 ! set diagonal of sub-block
     313         1270 :             V_blocks(sgfa1 - 1 + i, sgfa2 - 1 + i, kterm) = 1.0_dp
     314         2134 :             V_blocks(sgfa2 - 1 + i, sgfa1 - 1 + i, kterm) = 1.0_dp
     315              :          END DO
     316        31096 :          norm2 = SUM(V_blocks(:, :, kterm)**2)
     317        32764 :          V_blocks(:, :, kterm) = V_blocks(:, :, kterm)/SQRT(norm2) ! normalize
     318              :       END DO ! jshell
     319              :       END DO ! ishell
     320              :       END DO ! jset
     321              :       END DO ! iset
     322              : 
     323          195 :       CPASSERT(SIZE(V_blocks, 3) == kterm) ! ensure we generated all terms
     324              : 
     325          195 :       CALL timestop(handle)
     326          195 :    END SUBROUTINE linpot_rotinv_calc_terms
     327              : 
     328              : ! **************************************************************************************************
     329              : !> \brief Calculate force contribution from rotinv parametrization
     330              : !> \param qs_env ...
     331              : !> \param iatom ...
     332              : !> \param M_blocks ...
     333              : !> \param forces ...
     334              : ! **************************************************************************************************
     335           32 :    SUBROUTINE linpot_rotinv_calc_forces(qs_env, iatom, M_blocks, forces)
     336              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     337              :       INTEGER, INTENT(IN)                                :: iatom
     338              :       REAL(dp), DIMENSION(:, :, :), INTENT(IN)           :: M_blocks
     339              :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: forces
     340              : 
     341              :       CHARACTER(len=*), PARAMETER :: routineN = 'linpot_rotinv_calc_forces'
     342              : 
     343              :       INTEGER :: handle, i, ic, ikind, ipot, iset, ishell, ishell_abs, jatom, jkind, jset, jshell, &
     344              :          jshell_abs, kterm, la1_max, la1_min, la2_max, la2_min, lb_max, lb_min, lpot, N, na1, na2, &
     345              :          natoms, nb, ncfga1, ncfga2, ncfgb, npgfa1, npgfa2, npgfb, npots, nshells, pot_maxl, &
     346              :          sgfa1, sgfa2, sgla1, sgla2
     347              :       REAL(dp)                                           :: coeff, f, norm2, pot_beta, pot_weight, &
     348              :                                                             rpgfa_max, tab
     349              :       REAL(dp), DIMENSION(3)                             :: Ra, Rab, Rb
     350           32 :       REAL(dp), DIMENSION(:), POINTER                    :: rpgfa1, rpgfa2, rpgfb, zeta1, zeta2, zetb
     351           32 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_D, T1, T2
     352           32 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: block_M_full, dab
     353           32 :       REAL(dp), DIMENSION(:, :, :, :), POINTER           :: daab
     354              :       TYPE(cell_type), POINTER                           :: cell
     355              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     356           32 :       TYPE(pao_potential_type), DIMENSION(:), POINTER    :: ipao_potentials, jpao_potentials
     357           32 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     358           32 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     359              : 
     360           32 :       CALL timeset(routineN, handle)
     361              : 
     362              :       CALL get_qs_env(qs_env, &
     363              :                       natom=natoms, &
     364              :                       cell=cell, &
     365              :                       particle_set=particle_set, &
     366           32 :                       qs_kind_set=qs_kind_set)
     367              : 
     368           32 :       CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
     369           32 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, pao_potentials=ipao_potentials)
     370           32 :       npots = SIZE(ipao_potentials)
     371           66 :       nshells = SUM(basis_set%nshell)
     372           32 :       N = basis_set%nsgf ! primary basis-size
     373           32 :       CPASSERT(SIZE(M_blocks, 1) == N .AND. SIZE(M_blocks, 2) == N)
     374           32 :       kterm = 0 ! init counter
     375          128 :       ALLOCATE (block_D(N, N))
     376              : 
     377           64 :       DO ipot = 1, npots
     378           32 :          pot_maxl = ipao_potentials(ipot)%maxl ! taken from central atom
     379              : 
     380              :          ! build block_M_full
     381          160 :          ALLOCATE (block_M_full(N, N, pot_maxl/2 + 1))
     382         1048 :          block_M_full = 0.0_dp
     383           66 :          DO iset = 1, basis_set%nset
     384          102 :          DO jset = 1, iset
     385          170 :             DO ishell = 1, basis_set%nshell(iset)
     386          432 :             DO jshell = 1, basis_set%nshell(jset)
     387          296 :                IF (basis_set%l(ishell, iset) == 0 .AND. basis_set%l(jshell, jset) == 0) CYCLE ! covered by central terms
     388          166 :                ishell_abs = SUM(basis_set%nshell(1:iset - 1)) + ishell
     389          160 :                jshell_abs = SUM(basis_set%nshell(1:jset - 1)) + jshell
     390          158 :                IF (ishell_abs < jshell_abs) CYCLE
     391              :                ! find bounds of shell-pair
     392           98 :                sgfa1 = basis_set%first_sgf(ishell, iset)
     393           98 :                sgla1 = basis_set%last_sgf(ishell, iset)
     394           98 :                sgfa2 = basis_set%first_sgf(jshell, jset)
     395           98 :                sgla2 = basis_set%last_sgf(jshell, jset)
     396          296 :                DO lpot = 0, pot_maxl, 2
     397           98 :                   kterm = kterm + 1
     398          746 :                   block_M_full(sgfa1:sgla1, sgfa2:sgla2, lpot/2 + 1) = M_blocks(sgfa1:sgla1, sgfa2:sgla2, kterm)
     399         1174 :                   block_M_full(sgfa2:sgla2, sgfa1:sgla1, lpot/2 + 1) = M_blocks(sgfa2:sgla2, sgfa1:sgla1, kterm)
     400              :                END DO ! lpot
     401              :             END DO ! jshell
     402              :             END DO ! ishell
     403              :          END DO ! jset
     404              :          END DO ! iset
     405              : 
     406              :          ! setup description of potential
     407           32 :          lb_min = 0
     408           32 :          lb_max = pot_maxl
     409           32 :          ncfgb = ncoset(lb_max) - ncoset(lb_min - 1)
     410           32 :          npgfb = 1 ! number of exponents
     411           32 :          nb = npgfb*ncfgb
     412           32 :          ALLOCATE (rpgfb(npgfb), zetb(npgfb))
     413              : 
     414           66 :          DO iset = 1, basis_set%nset
     415          102 :          DO jset = 1, iset
     416              : 
     417              :             ! setup iset
     418           36 :             la1_max = basis_set%lmax(iset)
     419           36 :             la1_min = basis_set%lmin(iset)
     420           36 :             npgfa1 = basis_set%npgf(iset)
     421           36 :             ncfga1 = ncoset(la1_max) - ncoset(la1_min - 1)
     422           36 :             na1 = npgfa1*ncfga1
     423           36 :             zeta1 => basis_set%zet(:, iset)
     424           36 :             rpgfa1 => basis_set%pgf_radius(:, iset)
     425              : 
     426              :             ! setup jset
     427           36 :             la2_max = basis_set%lmax(jset)
     428           36 :             la2_min = basis_set%lmin(jset)
     429           36 :             npgfa2 = basis_set%npgf(jset)
     430           36 :             ncfga2 = ncoset(la2_max) - ncoset(la2_min - 1)
     431           36 :             na2 = npgfa2*ncfga2
     432           36 :             zeta2 => basis_set%zet(:, jset)
     433           36 :             rpgfa2 => basis_set%pgf_radius(:, jset)
     434              : 
     435              :             ! radius of most diffuse basis-function
     436          460 :             rpgfa_max = MAX(MAXVAL(rpgfa1), MAXVAL(rpgfa2))
     437              : 
     438              :             ! find bounds of set-pair and setup transformation matrices
     439           36 :             sgfa1 = basis_set%first_sgf(1, iset)
     440           36 :             sgla1 = sgfa1 + basis_set%nsgf_set(iset) - 1
     441           36 :             sgfa2 = basis_set%first_sgf(1, jset)
     442           36 :             sgla2 = sgfa2 + basis_set%nsgf_set(jset) - 1
     443           36 :             T1 => basis_set%scon(1:na1, sgfa1:sgla1)
     444           36 :             T2 => basis_set%scon(1:na2, sgfa2:sgla2)
     445              : 
     446              :             ! allocate space for integrals
     447          360 :             ALLOCATE (daab(na1, na2, nb, 3), dab(na1, na2, 3))
     448              : 
     449              :             ! loop over neighbors
     450          110 :             DO jatom = 1, natoms
     451           74 :                IF (jatom == iatom) CYCLE ! no self-interaction
     452           38 :                CALL get_atomic_kind(particle_set(jatom)%atomic_kind, kind_number=jkind)
     453           38 :                CALL get_qs_kind(qs_kind_set(jkind), pao_potentials=jpao_potentials)
     454           38 :                IF (SIZE(jpao_potentials) /= npots) THEN
     455            0 :                   CPABORT("Not all KINDs have the same number of PAO_POTENTIAL sections")
     456              :                END IF
     457              : 
     458              :                ! initialize exponents
     459           38 :                pot_weight = jpao_potentials(ipot)%weight ! taken from remote atom
     460           38 :                pot_beta = jpao_potentials(ipot)%beta ! taken from remote atom
     461           38 :                rpgfb(1) = jpao_potentials(ipot)%beta_radius ! taken from remote atom
     462           38 :                zetb(1) = pot_beta
     463              : 
     464              :                ! calculate direction
     465          152 :                Ra = particle_set(iatom)%r
     466          152 :                Rb = particle_set(jatom)%r
     467           38 :                Rab = pbc(ra, rb, cell)
     468              : 
     469              :                ! distance screening
     470          152 :                tab = SQRT(SUM(Rab**2))
     471           38 :                IF (rpgfa_max + rpgfb(1) < tab) CYCLE
     472              : 
     473              :                ! calculate actual integrals
     474        59774 :                daab = 0.0_dp
     475              :                CALL overlap_aab(la1_max=la1_max, la1_min=la1_min, npgfa1=npgfa1, rpgfa1=rpgfa1, zeta1=zeta1, &
     476              :                                 la2_max=la2_max, la2_min=la2_min, npgfa2=npgfa2, rpgfa2=rpgfa2, zeta2=zeta2, &
     477              :                                 lb_max=lb_max, lb_min=lb_min, npgfb=npgfb, rpgfb=rpgfb, zetb=zetb, &
     478           38 :                                 rab=Rab, daab=daab)
     479              : 
     480              :                ! sum neighbor contributions according to remote atom's weight and normalization
     481          150 :                DO lpot = 0, pot_maxl, 2
     482              :                   ! sum potential terms: POW(x**2 + y**2 + z**2, lpot/2)
     483        59660 :                   dab = 0.0_dp
     484           76 :                   DO ic = ncoset(lpot - 1) + 1, ncoset(lpot)
     485           38 :                      norm2 = (2.0_dp*pot_beta)**(-0.5_dp - lpot)*gamma1(lpot)
     486          152 :                      coeff = multinomial(lpot/2, indco(:, ic)/2)
     487       119320 :                      dab = dab + coeff*daab(:, :, ic, :)*pot_weight/SQRT(norm2)
     488              :                   END DO
     489          226 :                   DO i = 1, 3
     490              :                      ! transform into primary basis
     491         3750 :                      block_D = 0.0_dp
     492       728652 :                      block_D(sgfa1:sgla1, sgfa2:sgla2) = MATMUL(TRANSPOSE(T1), MATMUL(dab(:, :, i), T2))
     493         6306 :                      block_D(sgfa2:sgla2, sgfa1:sgla1) = TRANSPOSE(block_D(sgfa1:sgla1, sgfa2:sgla2))
     494              :                      ! calculate and add forces
     495         3750 :                      f = SUM(block_M_full(:, :, lpot/2 + 1)*block_D)
     496          114 :                      forces(iatom, i) = forces(iatom, i) - f
     497          152 :                      forces(jatom, i) = forces(jatom, i) + f
     498              :                   END DO
     499              :                END DO ! lpot
     500              :             END DO ! jatom
     501           70 :             DEALLOCATE (dab, daab)
     502              :          END DO ! jset
     503              :          END DO ! iset
     504           64 :          DEALLOCATE (rpgfb, zetb, block_M_full)
     505              :       END DO ! ipot
     506           32 :       DEALLOCATE (block_D)
     507              : 
     508           32 :       CALL timestop(handle)
     509           64 :    END SUBROUTINE linpot_rotinv_calc_forces
     510              : 
     511          382 : END MODULE pao_linpot_rotinv
        

Generated by: LCOV version 2.0-1