LCOV - code coverage report
Current view: top level - src - qs_cneo_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:b310db4) Lines: 98.4 % 62 61
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 Utility functions for CNEO-DFT
      10              : !>      (see J. Chem. Theory Comput. 2025, 21, 16, 7865–7877)
      11              : !> \par History
      12              : !>      08.2025 created [zc62]
      13              : !> \author Zehua Chen
      14              : ! **************************************************************************************************
      15              : MODULE qs_cneo_utils
      16              :    USE ao_util,                         ONLY: trace_r_AxB
      17              :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      18              :                                               gto_basis_set_type
      19              :    USE kinds,                           ONLY: dp
      20              :    USE memory_utilities,                ONLY: reallocate
      21              :    USE qs_harmonics_atom,               ONLY: get_none0_cg_list,&
      22              :                                               harmonics_atom_type
      23              : #include "./base/base_uses.f90"
      24              : 
      25              :    IMPLICIT NONE
      26              : 
      27              :    PRIVATE
      28              : 
      29              :    ! *** Global parameters ***
      30              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cneo_utils'
      31              : 
      32              :    ! *** Public subroutines ***
      33              :    PUBLIC :: atom_solve_cneo, cneo_gather, cneo_scatter, create_harmonics_atom_cneo, &
      34              :              get_maxl_CG_cneo
      35              : 
      36              : CONTAINS
      37              : 
      38              : ! **************************************************************************************************
      39              : !> \brief Mostly copied from qs_harmonics_atom::create_harmonics_atom
      40              : !> \param harmonics ...
      41              : !> \param my_CG ...
      42              : !> \param llmax ...
      43              : !> \param maxs ...
      44              : !> \param max_s_harm ...
      45              : ! **************************************************************************************************
      46            8 :    SUBROUTINE create_harmonics_atom_cneo(harmonics, my_CG, llmax, maxs, max_s_harm)
      47              : 
      48              :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
      49              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: my_CG
      50              :       INTEGER, INTENT(IN)                                :: llmax, maxs, max_s_harm
      51              : 
      52              :       INTEGER                                            :: i, is
      53              : 
      54            8 :       CPASSERT(ASSOCIATED(harmonics))
      55              : 
      56            8 :       harmonics%max_s_harm = max_s_harm
      57            8 :       harmonics%llmax = llmax
      58              : 
      59            8 :       NULLIFY (harmonics%my_CG, harmonics%my_CG_dxyz, harmonics%my_CG_dxyz_asym)
      60            8 :       CALL reallocate(harmonics%my_CG, 1, maxs, 1, maxs, 1, max_s_harm)
      61              : 
      62          208 :       DO i = 1, max_s_harm
      63         2008 :          DO is = 1, maxs
      64        36200 :             harmonics%my_CG(1:maxs, is, i) = my_CG(1:maxs, is, i)
      65              :          END DO
      66              :       END DO
      67              : 
      68            8 :    END SUBROUTINE create_harmonics_atom_cneo
      69              : 
      70              : ! **************************************************************************************************
      71              : !> \brief Mostly copied from qs_harmonics_atom::get_maxl_CG
      72              : !> \param harmonics ...
      73              : !> \param orb_basis ...
      74              : !> \param llmax ...
      75              : !> \param max_s_harm ...
      76              : ! **************************************************************************************************
      77           16 :    SUBROUTINE get_maxl_CG_cneo(harmonics, orb_basis, llmax, max_s_harm)
      78              : 
      79              :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
      80              :       TYPE(gto_basis_set_type), POINTER                  :: orb_basis
      81              :       INTEGER, INTENT(IN)                                :: llmax, max_s_harm
      82              : 
      83              :       INTEGER                                            :: is1, is2, itmp, max_iso_not0, nset
      84            8 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin
      85              : 
      86            0 :       CPASSERT(ASSOCIATED(harmonics))
      87              : 
      88            8 :       CALL get_gto_basis_set(gto_basis_set=orb_basis, lmax=lmax, lmin=lmin, nset=nset)
      89              : 
      90              :       !   *** Assign indices for the non null CG coefficients ***
      91            8 :       max_iso_not0 = 0
      92           80 :       DO is1 = 1, nset
      93          728 :          DO is2 = 1, nset
      94              :             CALL get_none0_cg_list(harmonics%my_CG, &
      95              :                                    lmin(is1), lmax(is1), lmin(is2), lmax(is2), &
      96          648 :                                    max_s_harm, llmax, max_iso_not0=itmp)
      97          720 :             max_iso_not0 = MAX(max_iso_not0, itmp)
      98              :          END DO ! is2
      99              :       END DO ! is1
     100            8 :       harmonics%max_iso_not0 = max_iso_not0
     101              : 
     102            8 :    END SUBROUTINE get_maxl_CG_cneo
     103              : 
     104              : ! **************************************************************************************************
     105              : !> \brief Mostly copied from atom_utils::atom_solve
     106              : !> \param hmat ...
     107              : !> \param f ...
     108              : !> \param umat ...
     109              : !> \param orb ...
     110              : !> \param ener ...
     111              : !> \param pmat ...
     112              : !> \param r ...
     113              : !> \param dist ...
     114              : !> \param nb ...
     115              : !> \param nv ...
     116              : ! **************************************************************************************************
     117          645 :    SUBROUTINE atom_solve_cneo(hmat, f, umat, orb, ener, pmat, r, dist, nb, nv)
     118              : 
     119              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: hmat
     120              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: f
     121              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: umat
     122              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: orb
     123              :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: ener
     124              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: pmat
     125              :       REAL(KIND=dp), DIMENSION(3), INTENT(INOUT)         :: r
     126              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: dist
     127              :       INTEGER, INTENT(IN)                                :: nb, nv
     128              : 
     129              :       INTEGER                                            :: info, lwork, m, n
     130          645 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: w, work
     131          645 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: a, b, h_fx
     132              : 
     133          645 :       CPASSERT(nb >= nv)
     134              : 
     135       356685 :       orb = 0._dp
     136          645 :       n = nb
     137          645 :       m = nv
     138          645 :       IF (n > 0 .AND. m > 0) THEN
     139          645 :          lwork = MAX(n*n, n + 100)
     140         7095 :          ALLOCATE (a(m, m), b(n, m), w(m), work(lwork))
     141         2580 :          IF (DOT_PRODUCT(f, f) /= 0.0_dp) THEN
     142         2396 :             ALLOCATE (h_fx(n, n))
     143              :             h_fx(1:n, 1:n) = hmat(1:n, 1:n) + f(1)*dist(1:n, 1:n, 1) + &
     144       331247 :                              f(2)*dist(1:n, 1:n, 2) + f(3)*dist(1:n, 1:n, 3)
     145          599 :             CALL dgemm("N", "N", n, m, n, 1.0_dp, h_fx, n, umat, n, 0.0_dp, b, n)
     146          599 :             DEALLOCATE (h_fx)
     147              :          ELSE
     148           46 :             CALL dgemm("N", "N", n, m, n, 1.0_dp, hmat, n, umat, n, 0.0_dp, b, n)
     149              :          END IF
     150          645 :          CALL dgemm("T", "N", m, m, n, 1.0_dp, umat, n, b, n, 0.0_dp, a, m)
     151          645 :          CALL dsyev("V", "U", m, a, m, w, work, lwork, info)
     152          645 :          CALL dgemm("N", "N", n, m, m, 1.0_dp, umat, n, a, m, 0.0_dp, b, n)
     153              : 
     154          645 :          m = MIN(m, SIZE(orb, 2))
     155       356685 :          orb(1:n, 1:m) = b(1:n, 1:m)
     156        15480 :          ener(1:m) = w(1:m)
     157              : 
     158          645 :          DEALLOCATE (a, b, w, work)
     159              : 
     160              :          ! calculate the density matrix using the orbital with the lowest orbital energy
     161       356685 :          pmat = 0.0_dp
     162          645 :          CALL dger(n, n, 1.0_dp, orb(:, 1), 1, orb(:, 1), 1, pmat, n)
     163              :          ! calculate the expectation position (basis center as the origin)
     164              :          r = [trace_r_AxB(dist(1:n, 1:n, 1), n, pmat, n, n, n), &
     165              :               trace_r_AxB(dist(1:n, 1:n, 2), n, pmat, n, n, n), &
     166         3225 :               trace_r_AxB(dist(1:n, 1:n, 3), n, pmat, n, n, n)]
     167              :       END IF
     168              : 
     169          645 :    END SUBROUTINE atom_solve_cneo
     170              : 
     171              : ! **************************************************************************************************
     172              : !> \brief Mostly copied from qs_oce_methods::prj_gather
     173              : !> \param ain ...
     174              : !> \param aout ...
     175              : !> \param nbas ...
     176              : !> \param n2oindex ...
     177              : ! **************************************************************************************************
     178           92 :    SUBROUTINE cneo_gather(ain, aout, nbas, n2oindex)
     179              : 
     180              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: ain
     181              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: aout
     182              :       INTEGER, INTENT(IN)                                :: nbas
     183              :       INTEGER, DIMENSION(:), POINTER                     :: n2oindex
     184              : 
     185              :       INTEGER                                            :: i, ip, j, jp
     186              : 
     187         2208 :       DO i = 1, nbas
     188         2116 :          ip = n2oindex(i)
     189        50876 :          DO j = 1, nbas
     190        48668 :             jp = n2oindex(j)
     191        50784 :             aout(j, i) = ain(jp, ip)
     192              :          END DO
     193              :       END DO
     194              : 
     195           92 :    END SUBROUTINE cneo_gather
     196              : 
     197              : ! **************************************************************************************************
     198              : !> \brief Mostly copied from qs_oce_methods::prj_scatter
     199              : !> \param ain ...
     200              : !> \param aout ...
     201              : !> \param nbas ...
     202              : !> \param n2oindex ...
     203              : ! **************************************************************************************************
     204          156 :    SUBROUTINE cneo_scatter(ain, aout, nbas, n2oindex)
     205              : 
     206              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: ain
     207              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: aout
     208              :       INTEGER, INTENT(IN)                                :: nbas
     209              :       INTEGER, DIMENSION(:), POINTER                     :: n2oindex
     210              : 
     211              :       INTEGER                                            :: i, ip, j, jp
     212              : 
     213         3744 :       DO i = 1, nbas
     214         3588 :          ip = n2oindex(i)
     215        86268 :          DO j = 1, nbas
     216        82524 :             jp = n2oindex(j)
     217        86112 :             aout(jp, ip) = aout(jp, ip) + ain(j, i)
     218              :          END DO
     219              :       END DO
     220              : 
     221          156 :    END SUBROUTINE cneo_scatter
     222              : 
     223              : END MODULE qs_cneo_utils
        

Generated by: LCOV version 2.0-1