LCOV - code coverage report
Current view: top level - src - gapw_unittest.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 95.5 % 67 64
Test Date: 2026-10-15 00:55: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            2 : PROGRAM gapw_unittest
       9              :    USE basis_set_types,                 ONLY: allocate_gto_basis_set,&
      10            2 :                                               create_primitive_basis_set,&
      11              :                                               deallocate_gto_basis_set,&
      12              :                                               gto_basis_set_type
      13              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      14              :    USE gapw_1c_basis_set,               ONLY: create_1c_basis
      15              :    USE hartree_local_methods,           ONLY: gapw_background_potential
      16              :    USE kinds,                           ONLY: dp
      17              :    USE libcp2k,                         ONLY: cp2k_finalize,&
      18              :                                               cp2k_init
      19              :    USE mathconstants,                   ONLY: fourpi,&
      20              :                                               pi
      21              :    USE orbital_pointers,                ONLY: init_orbital_pointers
      22              :    USE orbital_transformation_matrices, ONLY: init_spherical_harmonics
      23              : 
      24              :    IMPLICIT NONE
      25              : 
      26              :    INTEGER, PARAMETER :: nr = 1601, ng = 32
      27              :    REAL(dp), PARAMETER :: alpha = 1.4_dp, beta = 0.55_dp, box = 12.0_dp, dr = 0.00625_dp
      28              :    REAL(dp), PARAMETER :: charges(2) = [-1.0_dp, 0.3_dp]
      29              :    REAL(dp) :: rad2(nr), weights(nr), delta_rho(nr), potential(nr), shifted(nr)
      30              :    REAL(dp) :: q, g2, periodic_difference, local_difference, correction, error, h, eplus, eminus
      31              :    INTEGER :: i, ix, iy, iz, io_unit
      32              : 
      33            2 :    CALL cp2k_init()
      34            2 :    io_unit = cp_logger_get_default_io_unit()
      35            2 :    CALL check_1c_basis()
      36         3204 :    DO i = 1, nr
      37         3204 :       rad2(i) = ((i - 1)*dr)**2
      38              :    END DO
      39         3204 :    weights = 2.0_dp*dr/3.0_dp
      40         1602 :    weights(2:nr - 1:2) = 4.0_dp*dr/3.0_dp
      41            2 :    weights(1) = dr/3.0_dp
      42            2 :    weights(nr) = dr/3.0_dp
      43         3204 :    weights = weights*rad2
      44              : 
      45            6 :    DO i = 1, SIZE(charges)
      46            4 :       q = charges(i)
      47              :       ! Electron-minus-nuclear l=0 density. Both normalized Gaussians carry q,
      48              :       ! so their difference has zero monopole and a nonzero second moment.
      49              :       delta_rho = q*SQRT(fourpi)*((alpha/pi)**1.5_dp*EXP(-alpha*rad2) - &
      50         6408 :                                   (beta/pi)**1.5_dp*EXP(-beta*rad2))
      51            4 :       potential = gapw_background_potential(-q, box**3, rad2)
      52         6408 :       correction = SUM(potential*delta_rho*weights)
      53              : 
      54              :       ! Independent reference: exact reciprocal-space Coulomb energies of the
      55              :       ! two periodic Gaussians with G=0 omitted, minus their free-space energies.
      56              :       periodic_difference = 0.0_dp
      57          264 :       DO iz = -ng, ng
      58        17164 :          DO iy = -ng, ng
      59      1115660 :             DO ix = -ng, ng
      60      1098500 :                IF (ix == 0 .AND. iy == 0 .AND. iz == 0) CYCLE
      61      1098496 :                g2 = (2.0_dp*pi/box)**2*REAL(ix*ix + iy*iy + iz*iz, dp)
      62              :                periodic_difference = periodic_difference + &
      63      1115400 :                                      2.0_dp*pi*q*q/box**3/g2*(EXP(-g2/(2.0_dp*alpha)) - EXP(-g2/(2.0_dp*beta)))
      64              :             END DO
      65              :          END DO
      66              :       END DO
      67            4 :       local_difference = q*q*(SQRT(alpha) - SQRT(beta))/SQRT(2.0_dp*pi)
      68            4 :       error = ABS(periodic_difference - local_difference - correction)
      69            4 :       IF (io_unit > 0) WRITE (io_unit, '(A,F8.3,ES16.7)') "GAPW periodic Gaussian background:", q, error
      70            4 :       IF (error > 1.e-12_dp) ERROR STOP "GAPW background disagrees with periodic Gaussian electrostatics"
      71              : 
      72              :       ! The explicit volume derivative contributes E_background to each
      73              :       ! diagonal component of -dE/dstrain (local radial functions held fixed).
      74            4 :       h = 1.e-5_dp
      75            4 :       shifted = gapw_background_potential(-q, box**3*(1.0_dp + h), rad2)
      76         6408 :       eplus = SUM(shifted*delta_rho*weights)
      77            4 :       shifted = gapw_background_potential(-q, box**3*(1.0_dp - h), rad2)
      78         6408 :       eminus = SUM(shifted*delta_rho*weights)
      79            6 :       IF (ABS(-(eplus - eminus)/(2.0_dp*h) - correction) > 1.e-11_dp) THEN
      80            0 :          ERROR STOP "GAPW background volume derivative failed"
      81              :       END IF
      82              :    END DO
      83            2 :    potential = gapw_background_potential(0.0_dp, box**3, rad2)
      84         3204 :    IF (ANY(potential /= 0.0_dp)) ERROR STOP "Neutral cell has a background potential"
      85            2 :    CALL cp2k_finalize()
      86              : CONTAINS
      87              : 
      88              : ! **************************************************************************************************
      89              : !> \brief Check that one-centre basis extension retains diffuse exponents without duplicates.
      90              : ! **************************************************************************************************
      91            2 :    SUBROUTINE check_1c_basis()
      92              :       INTEGER, PARAMETER                                 :: expected(4) = [3, 4, 5, 7]
      93              :       REAL(KIND=dp), PARAMETER :: spacing(4) = [2.5_dp, 2.0_dp, 1.75_dp, 1.5_dp]
      94              : 
      95              :       INTEGER                                            :: level
      96              :       REAL(KIND=dp)                                      :: diffuse, ratio
      97              :       TYPE(gto_basis_set_type), POINTER                  :: extended, orbitals, seed
      98              : 
      99            2 :       NULLIFY (extended, orbitals, seed)
     100            2 :       CALL init_orbital_pointers(5)
     101            2 :       CALL init_spherical_harmonics(5, 0)
     102           10 :       DO level = 1, 4
     103            8 :          ratio = SPACING(level)
     104            8 :          CALL allocate_gto_basis_set(seed)
     105            8 :          seed%name = 'two-s-primitives'
     106            8 :          seed%norm_type = 2
     107            8 :          seed%nset = 1
     108            8 :          ALLOCATE (seed%lmin(1), seed%lmax(1), seed%npgf(1), seed%zet(2, 1))
     109           16 :          seed%lmin = 0
     110           16 :          seed%lmax = 0
     111           16 :          seed%npgf = 2
     112              :          ! The second extension candidate duplicates the second soft exponent.
     113              :          ! More diffuse, well-separated candidates must still be admitted.
     114           24 :          seed%zet(:, 1) = [1.0_dp, 1.0_dp/SQRT(ratio)]
     115            8 :          CALL create_primitive_basis_set(seed, orbitals)
     116           16 :          orbitals%set_radius = 0.0_dp
     117            8 :          CALL create_1c_basis(orbitals, orbitals, extended, level)
     118            8 :          diffuse = 1.0_dp/(ratio*SQRT(ratio))
     119            8 :          IF (io_unit > 0) WRITE (io_unit, '(A,I2,A,I3)') &
     120            4 :             'GAPW extension level ', level, ': added s primitives ', extended%npgf(2)
     121            8 :          IF (extended%npgf(2) /= expected(level)) ERROR STOP 'GAPW extension lost admissible diffuse exponents'
     122           46 :          IF (MINVAL(ABS(extended%zet(:extended%npgf(2), 2) - diffuse)) > 1.e-12_dp) THEN
     123            0 :             ERROR STOP 'GAPW extension is missing the first admissible diffuse exponent'
     124              :          END IF
     125           46 :          IF (MINVAL(ABS(extended%zet(:extended%npgf(2), 2) - seed%zet(2, 1))) < 1.e-12_dp) THEN
     126            0 :             ERROR STOP 'GAPW extension duplicated an existing soft exponent'
     127              :          END IF
     128            8 :          CALL deallocate_gto_basis_set(extended)
     129            8 :          CALL deallocate_gto_basis_set(orbitals)
     130           10 :          CALL deallocate_gto_basis_set(seed)
     131              :       END DO
     132            2 :    END SUBROUTINE check_1c_basis
     133              : END PROGRAM gapw_unittest
        

Generated by: LCOV version 2.0-1