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

            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 Expansion of the product of two real spherical harmonics in real
      10              : !>        spherical harmonics
      11              : !> \note
      12              : !>      The expansion coefficients are the Gaunt coefficients of the real
      13              : !>      spherical harmonics; they are obtained from libwignernj, which evaluates
      14              : !>      them in exact integer arithmetic. Historically CP2K called these
      15              : !>      "Clebsch-Gordon coefficients", which they are not, and built them from a
      16              : !>      table of factorial ratios that lost about one digit per two units of l.
      17              : !> \par History
      18              : !>      09.2026 created out of the five copies of this loop that lived in
      19              : !>              qs_rho_atom_methods, qs_tddfpt2_soc, qs_cneo_utils,
      20              : !>              xas_tdp_atom and generic_shg_integrals_init [Susi Lehtola]
      21              : !> \author Susi Lehtola
      22              : ! **************************************************************************************************
      23              : MODULE gaunt_coefficients
      24              : 
      25              :    USE kinds,                           ONLY: dp
      26              :    USE memory_utilities,                ONLY: reallocate
      27              :    USE orbital_pointers,                ONLY: indso,&
      28              :                                               nsoset
      29              :    USE wignernj_interface,              ONLY: real_gaunt
      30              : #include "../base/base_uses.f90"
      31              : 
      32              :    IMPLICIT NONE
      33              : 
      34              :    PRIVATE
      35              : 
      36              :    PUBLIC :: real_gaunt_coefficients
      37              : 
      38              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gaunt_coefficients'
      39              : 
      40              :    ! Coefficients below this threshold are not entered in the non-zero list
      41              :    REAL(KIND=dp), PARAMETER, PRIVATE :: cg_eps = 1.0E-8_dp
      42              : 
      43              : CONTAINS
      44              : 
      45              : ! **************************************************************************************************
      46              : !> \brief Calculate the expansion of the product of two real spherical harmonics
      47              : !>        in real spherical harmonics,
      48              : !>           S(l1,m1) S(l2,m2) = sum_lm my_cg(iso1,iso2,iso) S(l,m)
      49              : !> \param my_cg the expansion coefficients, allocated here; the pointer is
      50              : !>        INTENT(OUT), so the caller must not rely on its previous contents
      51              : !> \param maxl1 maximal angular momentum of the first harmonic
      52              : !> \param maxl2 maximal angular momentum of the second harmonic
      53              : !> \param llmax maximal angular momentum retained in the expansion
      54              : !> \param cg_none0_list list of the harmonics with a non-zero coefficient,
      55              : !>        allocated here if present
      56              : !> \param ncg_none0 number of harmonics with a non-zero coefficient,
      57              : !>        allocated here if present
      58              : ! **************************************************************************************************
      59         1852 :    SUBROUTINE real_gaunt_coefficients(my_cg, maxl1, maxl2, llmax, cg_none0_list, ncg_none0)
      60              : 
      61              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT), &
      62              :          POINTER                                         :: my_cg
      63              :       INTEGER, INTENT(IN)                                :: maxl1, maxl2, llmax
      64              :       INTEGER, DIMENSION(:, :, :), INTENT(OUT), &
      65              :          OPTIONAL, POINTER                               :: cg_none0_list
      66              :       INTEGER, DIMENSION(:, :), INTENT(OUT), OPTIONAL, &
      67              :          POINTER                                         :: ncg_none0
      68              : 
      69              :       CHARACTER(len=*), PARAMETER :: routineN = 'real_gaunt_coefficients'
      70              : 
      71              :       INTEGER                                            :: handle, ilist, im, iso, iso1, iso2, l1, &
      72              :                                                             l2, lp, m1, m2, mp(4), nlist, &
      73              :                                                             nlist_max, nsfunc, nsfunc1, nsfunc2
      74              :       LOGICAL                                            :: do_list
      75              : 
      76         1852 :       CALL timeset(routineN, handle)
      77              : 
      78         1852 :       CPASSERT(maxl1 >= 0)
      79         1852 :       CPASSERT(maxl2 >= 0)
      80         1852 :       CPASSERT(llmax >= 0)
      81              : 
      82         1852 :       nsfunc1 = nsoset(maxl1)
      83         1852 :       nsfunc2 = nsoset(maxl2)
      84         1852 :       nsfunc = nsoset(llmax)
      85              : 
      86         9260 :       ALLOCATE (my_cg(nsfunc1, nsfunc2, nsfunc))
      87      6609510 :       my_cg = 0.0_dp
      88              : 
      89        15904 :       DO iso1 = 1, nsfunc1
      90        14052 :          l1 = indso(1, iso1)
      91        14052 :          m1 = indso(2, iso1)
      92       161980 :          DO iso2 = 1, nsfunc2
      93       146076 :             l2 = indso(1, iso2)
      94       146076 :             m2 = indso(2, iso2)
      95              :             ! The product of two real harmonics only contains the azimuthal
      96              :             ! frequencies |m1+m2| and |m1-m2|; the cosine part goes to m >= 0
      97              :             ! and the sine part to m < 0, so of the four candidates below at
      98              :             ! most two have a non-vanishing coefficient. Rather than working
      99              :             ! out which one it is, we evaluate all four and let the selection
     100              :             ! rules zero out the rest.
     101       146076 :             mp(1) = ABS(m1 + m2)
     102       146076 :             mp(2) = -mp(1)
     103       146076 :             mp(3) = ABS(m1 - m2)
     104       146076 :             mp(4) = -mp(3)
     105       538290 :             DO lp = MOD(l1 + l2, 2), MIN(l1 + l2, llmax), 2
     106      2036886 :                DO im = 1, 4
     107      1512648 :                   IF (ABS(mp(im)) > lp) CYCLE
     108      1056312 :                   iso = nsoset(lp - 1) + lp + 1 + mp(im)
     109      1890810 :                   my_cg(iso1, iso2, iso) = real_gaunt(l1, m1, l2, m2, lp, mp(im))
     110              :                END DO
     111              :             END DO
     112              :          END DO
     113              :       END DO
     114              : 
     115         1852 :       do_list = PRESENT(cg_none0_list) .OR. PRESENT(ncg_none0)
     116         1852 :       IF (do_list) THEN
     117           72 :          CPASSERT(PRESENT(cg_none0_list))
     118           72 :          CPASSERT(PRESENT(ncg_none0))
     119           72 :          nlist_max = 6
     120          288 :          ALLOCATE (ncg_none0(nsfunc1, nsfunc2))
     121          360 :          ALLOCATE (cg_none0_list(nsfunc1, nsfunc2, nlist_max))
     122        15110 :          ncg_none0 = 0
     123        90732 :          cg_none0_list = 0
     124          682 :          DO iso1 = 1, nsfunc1
     125        14252 :             DO iso2 = 1, nsfunc2
     126        13570 :                nlist = 0
     127       790740 :                DO ilist = 1, nsfunc
     128       790740 :                   IF (ABS(my_cg(iso1, iso2, ilist)) > cg_eps) THEN
     129        37734 :                      nlist = nlist + 1
     130        37734 :                      IF (nlist > nlist_max) THEN
     131            8 :                         CALL reallocate(cg_none0_list, 1, nsfunc1, 1, nsfunc2, 1, nlist)
     132            8 :                         nlist_max = nlist
     133              :                      END IF
     134        37734 :                      cg_none0_list(iso1, iso2, nlist) = ilist
     135              :                   END IF
     136              :                END DO
     137        14180 :                ncg_none0(iso1, iso2) = nlist
     138              :             END DO
     139              :          END DO
     140              :       END IF
     141              : 
     142         1852 :       CALL timestop(handle)
     143              : 
     144         1852 :    END SUBROUTINE real_gaunt_coefficients
     145              : 
     146              : END MODULE gaunt_coefficients
        

Generated by: LCOV version 2.0-1