LCOV - code coverage report
Current view: top level - src - kpoint_smearing_unittest.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 94.0 % 67 63
Test Date: 2026-09-03 07:32:15 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 kpoint_smearing_unittest
       9            2 :    USE bibliography,                    ONLY: add_all_references
      10              :    USE input_constants,                 ONLY: smear_fermi_dirac,&
      11              :                                               smear_gaussian,&
      12              :                                               smear_mp,&
      13              :                                               smear_mv
      14              :    USE kinds,                           ONLY: dp
      15              :    USE kpoint_methods,                  ONLY: kpoint_smearing_edge_status
      16              :    USE qs_ot,                           ONLY: qs_ot_fixed_n_energy_hessian
      17              :    USE reference_manager,               ONLY: remove_all_references
      18              :    USE scf_control_types,               ONLY: smear_type
      19              :    USE smearing_utils,                  ONLY: Smearkp,&
      20              :                                               smearing_response_weight
      21              : 
      22              :    IMPLICIT NONE
      23              : 
      24              :    LOGICAL                                            :: first_fractional, has_weight, last_occupied
      25              :    LOGICAL, DIMENSION(2)                              :: last_occupied_spin
      26              :    REAL(KIND=dp), DIMENSION(2)                        :: weight
      27              :    REAL(KIND=dp), DIMENSION(3, 2, 2)                  :: occupation
      28              :    TYPE(smear_type)                                   :: smear
      29              : 
      30            2 :    CALL add_all_references()
      31            2 :    smear%do_smear = .TRUE.
      32            2 :    smear%eps_fermi_dirac = 1.0E-5_dp
      33            2 :    occupation = 0.0_dp
      34           14 :    occupation(1, :, :) = 1.0_dp
      35            2 :    weight = [1.0_dp, 0.0_dp]
      36              : 
      37            2 :    occupation(1, 2, 1) = 0.5_dp
      38            2 :    occupation(3, 2, 2) = 0.5_dp
      39              :    CALL kpoint_smearing_edge_status(occupation, weight, smear, 2, has_weight, &
      40            2 :                                     first_fractional, last_occupied, last_occupied_spin)
      41            2 :    IF (.NOT. has_weight) ERROR STOP "Positive K-point weight was not detected"
      42            2 :    IF (first_fractional) ERROR STOP "Zero-weight first-band occupation was included"
      43            2 :    IF (last_occupied) ERROR STOP "Zero-weight last-band occupation was included"
      44            6 :    IF (ANY(last_occupied_spin)) ERROR STOP "Zero-weight spin edge was included"
      45              : 
      46            2 :    weight(2) = 0.25_dp
      47              :    CALL kpoint_smearing_edge_status(occupation, weight, smear, 2, has_weight, &
      48            2 :                                     first_fractional, last_occupied, last_occupied_spin)
      49            2 :    IF (.NOT. first_fractional) ERROR STOP "Fractional first band was not detected"
      50            2 :    IF (.NOT. last_occupied) ERROR STOP "Occupied last band was not detected"
      51            2 :    IF (last_occupied_spin(1)) ERROR STOP "Wrong occupied spin edge was reported"
      52            2 :    IF (.NOT. last_occupied_spin(2)) ERROR STOP "Occupied spin edge was not reported"
      53              : 
      54            2 :    occupation = 0.0_dp
      55            6 :    occupation(1, :, 1) = 2.0_dp
      56              :    CALL kpoint_smearing_edge_status(occupation(:, :, 1:1), weight, smear, 1, has_weight, &
      57            2 :                                     first_fractional, last_occupied)
      58            2 :    IF (first_fractional) ERROR STOP "Restricted full occupation was classified as fractional"
      59              : 
      60            2 :    weight = 0.0_dp
      61              :    CALL kpoint_smearing_edge_status(occupation, weight, smear, 2, has_weight, &
      62            2 :                                     first_fractional, last_occupied, last_occupied_spin)
      63            2 :    IF (has_weight .OR. first_fractional .OR. last_occupied) THEN
      64            0 :       ERROR STOP "Zero-weight K-point set produced an edge status"
      65              :    END IF
      66              : 
      67            2 :    smear%do_smear = .FALSE.
      68            6 :    weight = 1.0_dp
      69              :    CALL kpoint_smearing_edge_status(occupation, weight, smear, 2, has_weight, &
      70            2 :                                     first_fractional, last_occupied, last_occupied_spin)
      71            2 :    IF (has_weight .OR. first_fractional .OR. last_occupied) THEN
      72            0 :       ERROR STOP "Disabled smearing produced an edge status"
      73              :    END IF
      74              : 
      75            2 :    CALL test_fixed_n_smearing_response()
      76            2 :    CALL remove_all_references()
      77              : 
      78              : CONTAINS
      79              : 
      80              : ! **************************************************************************************************
      81              : !> \brief Check the fixed-N occupation response for every supported K-point smearing method.
      82              : ! **************************************************************************************************
      83            2 :    SUBROUTINE test_fixed_n_smearing_response()
      84              :       INTEGER, PARAMETER                                 :: nkpoint = 2, nstate = 5
      85              :       REAL(KIND=dp), PARAMETER                           :: fd_step = 1.0E-6_dp, maxocc = 2.0_dp, &
      86              :                                                             sigma = 0.15_dp, TARGET = 4.3_dp
      87              : 
      88              :       INTEGER                                            :: ikpoint, imethod
      89              :       INTEGER, DIMENSION(4)                              :: methods
      90              :       REAL(KIND=dp)                                      :: error, kTS, mu, response_sum
      91              :       REAL(KIND=dp), DIMENSION(nkpoint)                  :: kpoint_weight
      92              :       REAL(KIND=dp), DIMENSION(nstate*nkpoint)           :: fd_response, flat_direction, &
      93              :                                                             predicted_response
      94              :       REAL(KIND=dp), &
      95              :          DIMENSION(nstate*nkpoint, nstate*nkpoint)       :: hessian
      96              :       REAL(KIND=dp), DIMENSION(nstate, nkpoint) :: direction, eigenvalue, eigenvalue_minus, &
      97              :          eigenvalue_plus, occupation, occupation_minus, occupation_plus, response
      98              : 
      99            2 :       methods(:) = [smear_fermi_dirac, smear_gaussian, smear_mp, smear_mv]
     100            2 :       kpoint_weight(:) = [0.4_dp, 0.6_dp]
     101           12 :       eigenvalue(:, 1) = [-0.38_dp, -0.14_dp, 0.02_dp, 0.23_dp, 0.52_dp]
     102           12 :       eigenvalue(:, 2) = [-0.31_dp, -0.08_dp, 0.07_dp, 0.28_dp, 0.61_dp]
     103           12 :       direction(:, 1) = [0.13_dp, -0.07_dp, 0.11_dp, -0.04_dp, 0.09_dp]
     104           12 :       direction(:, 2) = [-0.08_dp, 0.05_dp, -0.12_dp, 0.06_dp, -0.03_dp]
     105            2 :       flat_direction(:) = RESHAPE(direction, [nstate*nkpoint])
     106              : 
     107           10 :       DO imethod = 1, SIZE(methods)
     108              :          CALL Smearkp(occupation, mu, kTS, eigenvalue, TARGET, kpoint_weight, sigma, maxocc, &
     109            8 :                       methods(imethod))
     110           24 :          DO ikpoint = 1, nkpoint
     111              :             CALL smearing_response_weight( &
     112              :                response(:, ikpoint), occupation(:, ikpoint), eigenvalue(:, ikpoint), mu, sigma, &
     113           16 :                maxocc, nstate, methods(imethod))
     114          104 :             response(:, ikpoint) = kpoint_weight(ikpoint)*response(:, ikpoint)
     115              :          END DO
     116          104 :          response_sum = SUM(response)
     117            8 :          IF (ABS(response_sum) <= EPSILON(response_sum)) THEN
     118            0 :             ERROR STOP "Singular fixed-N smearing response in unit test"
     119              :          END IF
     120           56 :          IF ((methods(imethod) == smear_mp .OR. methods(imethod) == smear_mv) .AND. &
     121              :              .NOT. ANY(response < 0.0_dp)) THEN
     122            0 :             ERROR STOP "Signed smearing-response branch was not exercised"
     123              :          END IF
     124              :          CALL qs_ot_fixed_n_energy_hessian( &
     125            8 :             RESHAPE(response, [nstate*nkpoint]), response_sum, hessian)
     126              : 
     127          104 :          eigenvalue_plus(:, :) = eigenvalue + fd_step*direction
     128          104 :          eigenvalue_minus(:, :) = eigenvalue - fd_step*direction
     129              :          CALL Smearkp(occupation_plus, mu, kTS, eigenvalue_plus, TARGET, kpoint_weight, sigma, &
     130            8 :                       maxocc, methods(imethod))
     131              :          CALL Smearkp(occupation_minus, mu, kTS, eigenvalue_minus, TARGET, kpoint_weight, sigma, &
     132            8 :                       maxocc, methods(imethod))
     133           24 :          DO ikpoint = 1, nkpoint
     134              :             fd_response((ikpoint - 1)*nstate + 1:ikpoint*nstate) = &
     135              :                kpoint_weight(ikpoint)*(occupation_plus(:, ikpoint) - &
     136          104 :                                        occupation_minus(:, ikpoint))/(2.0_dp*fd_step)
     137              :          END DO
     138          976 :          predicted_response(:) = -MATMUL(hessian, flat_direction)
     139           88 :          error = MAXVAL(ABS(fd_response - predicted_response))
     140           88 :          error = MAX(error, ABS(SUM(fd_response)))
     141          976 :          error = MAX(error, MAXVAL(ABS(MATMUL(hessian, SPREAD(1.0_dp, 1, nstate*nkpoint)))))
     142           10 :          IF (error > 2.0E-6_dp) ERROR STOP "Fixed-N smearing response finite difference failed"
     143              :       END DO
     144              : 
     145            2 :    END SUBROUTINE test_fixed_n_smearing_response
     146              : 
     147              : END PROGRAM kpoint_smearing_unittest
        

Generated by: LCOV version 2.0-1