LCOV - code coverage report
Current view: top level - src/aobasis - ai_contraction_sphi.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 93.2 % 103 96
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 4 4

            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 Contraction of integrals over primitive Cartesian Gaussians based on the contraction
      10              : !>        matrix sphi which is part of the gto_basis_set_type
      11              : !> \par History
      12              : !>      -added abc_contract_xsmm routine, A. Bussy (04.2020)
      13              : !> \author Dorothea Golze (05.2016)
      14              : ! **************************************************************************************************
      15              : MODULE ai_contraction_sphi
      16              : 
      17              :    USE kinds, ONLY: dp, int_8
      18              : #if defined(__LIBXS)
      19              :    USE LIBXS_JIT, ONLY: libxs_gemm_config_t, libxs_gemm_dispatch, &
      20              :                         libxs_gemm_call, LIBXS_DATATYPE_F64, C_LOC
      21              : #endif
      22              : 
      23              : #include "../base/base_uses.f90"
      24              : 
      25              :    IMPLICIT NONE
      26              : 
      27              :    PRIVATE
      28              : 
      29              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'ai_contraction_sphi'
      30              : 
      31              :    PUBLIC :: ab_contract, abc_contract, abcd_contract, abc_contract_xsmm
      32              : 
      33              : CONTAINS
      34              : 
      35              : ! **************************************************************************************************
      36              : !> \brief contract overlap integrals (a,b) and transfer to spherical Gaussians
      37              : !> \param abint contracted, normalized integrals of spherical Gaussians
      38              : !> \param sab uncontracted, unnormalized integrals of primitive Cartesian Gaussians
      39              : !> \param sphi_a contraction matrix for center a
      40              : !> \param sphi_b contraction matrix for center b
      41              : !> \param ncoa number of cartesian orbitals on a
      42              : !> \param ncob number of cartesian orbitals on b
      43              : !> \param nsgfa number of spherical Gaussian functions on a
      44              : !> \param nsgfb number of spherical Gaussian functions on b
      45              : ! **************************************************************************************************
      46      1292952 :    SUBROUTINE ab_contract(abint, sab, sphi_a, sphi_b, ncoa, ncob, nsgfa, nsgfb)
      47              : 
      48              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: abint
      49              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: sab, sphi_a, sphi_b
      50              :       INTEGER, INTENT(IN)                                :: ncoa, ncob, nsgfa, nsgfb
      51              : 
      52              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'ab_contract'
      53              : 
      54              :       INTEGER                                            :: handle
      55      1292952 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: cpp
      56              : 
      57      1292952 :       CALL timeset(routineN, handle)
      58              : 
      59      1292952 :       CPASSERT(ncob <= SIZE(sab, 2))
      60              : 
      61      1292952 :       IF ((nsgfa*ncob*(ncoa + nsgfb)) <= (nsgfb*ncoa*(ncob + nsgfa))) THEN ! (sphi_a x sab) x sphi_b
      62      3515364 :          ALLOCATE (cpp(nsgfa, ncob))
      63              :          ! [nsgfa,ncoa] x [ncoa,ncob] -> [nsgfa,ncob]
      64     24712188 :          CALL dgemm("T", "N", nsgfa, ncob, ncoa, 1._dp, sphi_a, SIZE(sphi_a, 1), sab, SIZE(sab, 1), 0.0_dp, cpp, nsgfa)
      65              :          ! [nsgfa,ncob] x [ncob,nsgfb] -> [nsgfa,nsgfb]
      66              :          CALL dgemm("N", "N", nsgfa, nsgfb, ncob, 1._dp, cpp, nsgfa, sphi_b, SIZE(sphi_b, 1), 0.0_dp, &
      67     55412391 :                     abint, SIZE(abint, 1))
      68              :       ELSE ! sphi_a x (sab x sphi_b)
      69      1656444 :          ALLOCATE (cpp(ncoa, nsgfb))
      70              :          ! [ncoa,ncob] x [ncob,nsgfb] -> [ncoa,nsgfb]
      71      8345071 :          CALL dgemm("N", "N", ncoa, nsgfb, ncob, 1._dp, sab, SIZE(sab, 1), sphi_b, SIZE(sphi_b, 1), 0.0_dp, cpp, ncoa)
      72              :          ! [nsgfa,ncoa] x [ncoa,nsgfb] -> [nsgfa,nsgfb]
      73              :          CALL dgemm("T", "N", nsgfa, nsgfb, ncoa, 1._dp, sphi_a, SIZE(sphi_a, 1), cpp, ncoa, 0.0_dp, &
      74     14508899 :                     abint, SIZE(abint, 1))
      75              :       END IF
      76              : 
      77      1292952 :       DEALLOCATE (cpp)
      78              : 
      79      1292952 :       CALL timestop(handle)
      80              : 
      81      1292952 :    END SUBROUTINE ab_contract
      82              : 
      83              : ! **************************************************************************************************
      84              : !> \brief contract three-center overlap integrals (a,b,c) and transfer
      85              : !>        to spherical Gaussians
      86              : !> \param abcint contracted, normalized integrals of spherical Gaussians
      87              : !> \param sabc uncontracted, unnormalized integrals of primitive Cartesian Gaussians
      88              : !> \param sphi_a contraction matrix for center a
      89              : !> \param sphi_b contraction matrix for center b
      90              : !> \param sphi_c contraction matrix for center c
      91              : !> \param ncoa number of cartesian orbitals on a
      92              : !> \param ncob number of cartesian orbitals on b
      93              : !> \param ncoc number of cartesian orbitals on c
      94              : !> \param nsgfa number of spherical Gaussian functions on a
      95              : !> \param nsgfb number of spherical Gaussian functions on b
      96              : !> \param nsgfc number of spherical Gaussian functions on c
      97              : ! **************************************************************************************************
      98       207072 :    SUBROUTINE abc_contract(abcint, sabc, sphi_a, sphi_b, sphi_c, ncoa, ncob, ncoc, &
      99              :                            nsgfa, nsgfb, nsgfc)
     100              : 
     101              :       REAL(KIND=dp), DIMENSION(:, :, :)                  :: abcint, sabc
     102              :       REAL(KIND=dp), DIMENSION(:, :)                     :: sphi_a, sphi_b, sphi_c
     103              :       INTEGER, INTENT(IN)                                :: ncoa, ncob, ncoc, nsgfa, nsgfb, nsgfc
     104              : 
     105              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'abc_contract'
     106              : 
     107              :       INTEGER                                            :: handle, i, m1, m2, m3, msphia, msphib, &
     108              :                                                             msphic, mx
     109       207072 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: tmp
     110              : 
     111       207072 :       CALL timeset(routineN, handle)
     112              : 
     113       207072 :       CPASSERT(SIZE(abcint, 1) == nsgfa)
     114       207072 :       CPASSERT(SIZE(abcint, 2) == nsgfb)
     115              : 
     116       207072 :       msphia = SIZE(sphi_a, 1)
     117       207072 :       msphib = SIZE(sphi_b, 1)
     118       207072 :       msphic = SIZE(sphi_c, 1)
     119              : 
     120       207072 :       m1 = SIZE(sabc, 1)
     121       207072 :       m2 = SIZE(sabc, 2)
     122       207072 :       m3 = SIZE(sabc, 3)
     123       207072 :       mx = MAX(m2, nsgfb)
     124              : 
     125              :       ! ALLOCATE (cpp(nsgfa, m2, m3), cpc(nsgfa, nsgfb, m3))
     126      1035360 :       ALLOCATE (tmp(nsgfa, mx, m3 + 1))
     127              : 
     128       207072 :       CALL dgemm("T", "N", nsgfa, m2*m3, ncoa, 1._dp, sphi_a, msphia, sabc, m1, 0.0_dp, tmp(:, :, 2), nsgfa)
     129      1959016 :       DO i = 1, m3
     130              :          CALL dgemm("N", "N", nsgfa, nsgfb, ncob, 1._dp, tmp(:, :, i + 1), nsgfa, sphi_b, msphib, &
     131      1959016 :                     0.0_dp, tmp(:, :, i), nsgfa)
     132              :       END DO
     133              :       CALL dgemm("N", "N", nsgfa*nsgfb, nsgfc, ncoc, 1._dp, tmp, nsgfa*mx, sphi_c, msphic, 0.0_dp, &
     134      1236604 :                  abcint, nsgfa*nsgfb)
     135              : 
     136       207072 :       DEALLOCATE (tmp)
     137              : 
     138       207072 :       CALL timestop(handle)
     139              : 
     140       207072 :    END SUBROUTINE abc_contract
     141              : 
     142              : ! **************************************************************************************************
     143              : !> \brief contract four-center overlap integrals (a,b,c,d) and transfer
     144              : !>        to spherical Gaussians
     145              : !> \param abcdint contracted, normalized integrals of spherical Gaussians
     146              : !> \param sabcd uncontracted, unnormalized integrals of primitive Cartesian Gaussians
     147              : !> \param sphi_a contraction matrix for center a
     148              : !> \param sphi_b contraction matrix for center b
     149              : !> \param sphi_c contraction matrix for center c
     150              : !> \param sphi_d contraction matrix for center d
     151              : !> \param ncoa number of cartesian orbitals on a
     152              : !> \param ncob number of cartesian orbitals on b
     153              : !> \param ncoc number of cartesian orbitals on c
     154              : !> \param ncod number of cartesian orbitals on d
     155              : !> \param nsgfa number of spherical Gaussian functions on a
     156              : !> \param nsgfb number of spherical Gaussian functions on b
     157              : !> \param nsgfc number of spherical Gaussian functions on c
     158              : !> \param nsgfd number of spherical Gaussian functions on d
     159              : ! **************************************************************************************************
     160            9 :    SUBROUTINE abcd_contract(abcdint, sabcd, sphi_a, sphi_b, sphi_c, sphi_d, ncoa, ncob, &
     161              :                             ncoc, ncod, nsgfa, nsgfb, nsgfc, nsgfd)
     162              : 
     163              :       REAL(KIND=dp), DIMENSION(:, :, :, :), &
     164              :          INTENT(INOUT)                                   :: abcdint
     165              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(IN)   :: sabcd
     166              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: sphi_a, sphi_b, sphi_c, sphi_d
     167              :       INTEGER, INTENT(IN)                                :: ncoa, ncob, ncoc, ncod, nsgfa, nsgfb, &
     168              :                                                             nsgfc, nsgfd
     169              : 
     170              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'abcd_contract'
     171              : 
     172              :       INTEGER                                            :: handle, isgfc, isgfd, m1, m2, m3, m4, &
     173              :                                                             msphia, msphib, msphic, msphid
     174            9 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: temp_cccc
     175            9 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: cpcc
     176            9 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: cppc, cppp
     177              : 
     178            9 :       CALL timeset(routineN, handle)
     179              : 
     180            9 :       msphia = SIZE(sphi_a, 1)
     181            9 :       msphib = SIZE(sphi_b, 1)
     182            9 :       msphic = SIZE(sphi_c, 1)
     183            9 :       msphid = SIZE(sphi_d, 1)
     184              : 
     185            9 :       m1 = SIZE(sabcd, 1)
     186            9 :       m2 = SIZE(sabcd, 2)
     187            9 :       m3 = SIZE(sabcd, 3)
     188            9 :       m4 = SIZE(sabcd, 4)
     189              : 
     190              :       ALLOCATE (cppp(nsgfa, m2, m3, m4), cppc(nsgfa, m2, m3, nsgfd), &
     191          162 :                 cpcc(nsgfa, m2, nsgfc), temp_cccc(nsgfa, nsgfb))
     192              : 
     193              :       CALL dgemm("T", "N", nsgfa, m2*m3*m4, ncoa, 1._dp, sphi_a, msphia, sabcd, m1, &
     194            9 :                  0.0_dp, cppp, nsgfa)
     195              :       CALL dgemm("N", "N", nsgfa*m2*m3, nsgfd, ncod, 1._dp, cppp, nsgfa*m2*m3, &
     196            9 :                  sphi_d, msphid, 0.0_dp, cppc, nsgfa*m2*m3)
     197              : 
     198           45 :       DO isgfd = 1, nsgfd
     199              :          ! Full leading-dimension slices are contiguous; reuse cpcc for each spherical d.
     200              :          CALL dgemm("N", "N", nsgfa*m2, nsgfc, ncoc, 1._dp, cppc(:, :, :, isgfd), nsgfa*m2, &
     201           36 :                     sphi_c, msphic, 0.0_dp, cpcc, nsgfa*m2)
     202          189 :          DO isgfc = 1, nsgfc
     203              :             CALL dgemm("N", "N", nsgfa, nsgfb, ncob, 1._dp, cpcc(:, :, isgfc), nsgfa, sphi_b, &
     204          144 :                        msphib, 0.0_dp, temp_cccc, nsgfa)
     205              :             ! The caller's output block can be strided, so scatter from a contiguous buffer.
     206         3060 :             abcdint(:, :, isgfc, isgfd) = temp_cccc(:, :)
     207              :          END DO
     208              :       END DO
     209              : 
     210            9 :       DEALLOCATE (cpcc, cppc, cppp, temp_cccc)
     211              : 
     212            9 :       CALL timestop(handle)
     213              : 
     214            9 :    END SUBROUTINE abcd_contract
     215              : 
     216              : ! **************************************************************************************************
     217              : !> \brief 3-center contraction routine from primitive cartesian Gaussians to spherical Gaussian
     218              : !>        functions using BLAS dgemm.
     219              : !>        Requires pre-transposition of the sphi_a array. The call-side shall DEALLOCATE buffers
     220              : !>        end of scope or after last use. This function ALLOCATEs or grows the work buffers
     221              : !>        as necessary.
     222              : !> \param abcint contracted integrals
     223              : !> \param sabc uncontracted integrals
     224              : !> \param sphi_a assumed to have dimensions nsgfa x ncoa
     225              : !> \param sphi_b assumed to have dimensions ncob x nsgfb
     226              : !> \param sphi_c assumed to have dimensions ncoc x nsgfc
     227              : !> \param ncoa ...
     228              : !> \param ncob ...
     229              : !> \param ncoc ...
     230              : !> \param nsgfa ...
     231              : !> \param nsgfb ...
     232              : !> \param nsgfc ...
     233              : !> \param cpp_buffer Buffer used for intermediate results (automatically allocated).
     234              : !> \param ccp_buffer Buffer used for intermediate results (automatically allocated).
     235              : !> \param prefac Prefactor which is finally multiplied into abcint (default: 1.0).
     236              : !> \param pstfac Factor used to consider initial abcint (default: 0.0).
     237              : ! **************************************************************************************************
     238      6850397 :    SUBROUTINE abc_contract_xsmm(abcint, sabc, sphi_a, sphi_b, sphi_c, ncoa, ncob, ncoc, &
     239              :                                 nsgfa, nsgfb, nsgfc, cpp_buffer, ccp_buffer, prefac, pstfac)
     240              : 
     241              :       REAL(KIND=dp), DIMENSION(:, :, :)           :: abcint
     242              :       REAL(KIND=dp), DIMENSION(*), INTENT(IN), TARGET :: sabc
     243              :       REAL(KIND=dp), DIMENSION(:, :), CONTIGUOUS, INTENT(IN), TARGET :: sphi_a, sphi_b, sphi_c
     244              :       INTEGER, INTENT(IN)                         :: ncoa, ncob, ncoc, nsgfa, nsgfb, nsgfc
     245              :       REAL(KIND=dp), DIMENSION(:), ALLOCATABLE, TARGET :: cpp_buffer, ccp_buffer
     246              :       REAL(KIND=dp), INTENT(IN), OPTIONAL         :: prefac, pstfac
     247              : 
     248              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'abc_contract_xsmm'
     249              : 
     250              :       REAL(KIND=dp)                                           :: alpha, beta
     251              :       INTEGER(KIND=int_8)                                     :: cpp_size, ccp_size
     252              :       INTEGER                                                 :: handle, i
     253              :       LOGICAL                                                 :: ab_first
     254              : #if defined(__LIBXS)
     255              :       TYPE(libxs_gemm_config_t) :: cfg1, cfg2
     256              :       INTEGER :: rc1, rc2
     257              : #endif
     258              : 
     259      6850397 :       CALL timeset(routineN, handle)
     260              : 
     261      6850397 :       alpha = 1.0_dp
     262      6850397 :       IF (PRESENT(prefac)) alpha = prefac
     263              : 
     264      6850397 :       beta = 0.0_dp
     265      6850397 :       IF (PRESENT(pstfac)) beta = pstfac
     266              : 
     267              :       ! M*N*K FLOPS are used to decide if contracting (AB)C vs A(BC)
     268      6850397 :       IF ((nsgfa*ncob*(ncoa + nsgfb)) <= (ncoa*nsgfb*(ncob + nsgfa))) THEN
     269      6850397 :          cpp_size = nsgfa*ncob
     270      6850397 :          ab_first = .TRUE.
     271              :       ELSE
     272      1713235 :          cpp_size = ncoa*nsgfb
     273      1713235 :          ab_first = .FALSE.
     274              :       END IF
     275              : 
     276      6850397 :       ccp_size = nsgfa*nsgfb*ncoc
     277      6850397 :       IF (.NOT. ALLOCATED(ccp_buffer)) THEN
     278        26622 :          ALLOCATE (ccp_buffer(ccp_size))
     279      6841523 :       ELSE IF (SIZE(ccp_buffer) < ccp_size) THEN
     280        35320 :          DEALLOCATE (ccp_buffer)
     281       105960 :          ALLOCATE (ccp_buffer(ccp_size))
     282              :       END IF
     283              : 
     284      6850397 :       IF (.NOT. ALLOCATED(cpp_buffer)) THEN
     285        26622 :          ALLOCATE (cpp_buffer(cpp_size))
     286      6841523 :       ELSE IF (SIZE(cpp_buffer) < cpp_size) THEN
     287        12541 :          DEALLOCATE (cpp_buffer)
     288        37623 :          ALLOCATE (cpp_buffer(cpp_size))
     289              :       END IF
     290              : 
     291              : #if defined(__LIBXS)
     292      6850397 :       IF (ab_first) THEN
     293              :          rc1 = libxs_gemm_dispatch(cfg1, LIBXS_DATATYPE_F64, 'N', 'N', &
     294      5137162 :                                    nsgfa, ncob, ncoa, nsgfa, ncoa, nsgfa, 1.0D0, 0.0D0)
     295              :          rc2 = libxs_gemm_dispatch(cfg2, LIBXS_DATATYPE_F64, 'N', 'N', &
     296      5137162 :                                    nsgfa, nsgfb, ncob, nsgfa, ncob, nsgfa, 1.0D0, 0.0D0)
     297              :       ELSE
     298              :          rc1 = libxs_gemm_dispatch(cfg1, LIBXS_DATATYPE_F64, 'N', 'N', &
     299      1713235 :                                    ncoa, nsgfb, ncob, ncoa, ncob, ncoa, 1.0D0, 0.0D0)
     300              :          rc2 = libxs_gemm_dispatch(cfg2, LIBXS_DATATYPE_F64, 'N', 'N', &
     301      1713235 :                                    nsgfa, nsgfb, ncoa, nsgfa, ncoa, nsgfa, 1.0D0, 0.0D0)
     302              :       END IF
     303      6850397 :       IF (0 /= rc1 .AND. 0 /= rc2) THEN
     304      6850397 :          IF (ab_first) THEN
     305     45595316 :             DO i = 0, ncoc - 1
     306              :                CALL libxs_gemm_call(cfg1, C_LOC(sphi_a(1, 1)), &
     307     40458154 :                                     C_LOC(sabc(i*ncoa*ncob + 1)), C_LOC(cpp_buffer(1)))
     308              :                CALL libxs_gemm_call(cfg2, C_LOC(cpp_buffer(1)), &
     309     45595316 :                                     C_LOC(sphi_b(1, 1)), C_LOC(ccp_buffer(i*nsgfa*nsgfb + 1)))
     310              :             END DO
     311              :          ELSE
     312     16781137 :             DO i = 0, ncoc - 1
     313              :                CALL libxs_gemm_call(cfg1, C_LOC(sabc(i*ncoa*ncob + 1)), &
     314     15067902 :                                     C_LOC(sphi_b(1, 1)), C_LOC(cpp_buffer(1)))
     315              :                CALL libxs_gemm_call(cfg2, C_LOC(sphi_a(1, 1)), &
     316     16781137 :                                     C_LOC(cpp_buffer(1)), C_LOC(ccp_buffer(i*nsgfa*nsgfb + 1)))
     317              :             END DO
     318              :          END IF
     319              :       ELSE
     320              : #endif
     321            0 :          IF (ab_first) THEN ! (AB)C
     322            0 :             DO i = 0, ncoc - 1
     323              :                CALL dgemm("N", "N", nsgfa, ncob, ncoa, 1.0_dp, sphi_a, nsgfa, sabc(i*ncoa*ncob + 1), &
     324            0 :                           ncoa, 0.0_dp, cpp_buffer, nsgfa)
     325              :                CALL dgemm("N", "N", nsgfa, nsgfb, ncob, 1.0_dp, cpp_buffer, nsgfa, sphi_b, ncob, 0.0_dp, &
     326            0 :                           ccp_buffer(i*nsgfa*nsgfb + 1), nsgfa)
     327              :             END DO
     328              :          ELSE ! A(BC)
     329            0 :             DO i = 0, ncoc - 1
     330              :                CALL dgemm("N", "N", ncoa, nsgfb, ncob, 1.0_dp, sabc(i*ncoa*ncob + 1), ncoa, sphi_b, &
     331            0 :                           ncob, 0.0_dp, cpp_buffer, ncoa)
     332              :                CALL dgemm("N", "N", nsgfa, nsgfb, ncoa, 1.0_dp, sphi_a, nsgfa, cpp_buffer, ncoa, 0.0_dp, &
     333            0 :                           ccp_buffer(i*nsgfa*nsgfb + 1), nsgfa)
     334              :             END DO
     335              :          END IF
     336              : #if defined(__LIBXS)
     337              :       END IF
     338              : #endif
     339              :       ! contractions over c: [nsgfa*nsgfb,ncoc] x [ncoc,nsgfc] -> [sgfa*nsgfb,nsgfc]
     340              :       CALL dgemm("N", "N", nsgfa*nsgfb, nsgfc, ncoc, alpha, ccp_buffer, nsgfa*nsgfb, &
     341      6850397 :                  sphi_c, ncoc, beta, abcint, nsgfa*nsgfb)
     342              : 
     343      6850397 :       CALL timestop(handle)
     344              : 
     345      6850397 :    END SUBROUTINE abc_contract_xsmm
     346              : 
     347              : END MODULE ai_contraction_sphi
        

Generated by: LCOV version 2.0-1