LCOV - code coverage report
Current view: top level - src - qs_charge_mixing_unittest.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:62906da) Lines: 96.0 % 75 72
Test Date: 2026-10-24 01:17: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 qs_charge_mixing_unittest
       9            2 :    USE ieee_arithmetic, ONLY: ieee_is_finite
      10              :    USE kinds, ONLY: dp
      11              :    USE message_passing, ONLY: mp_para_env_type, &
      12              :                               mp_world_finalize, &
      13              :                               mp_world_init
      14              :    USE qs_charge_mixing, ONLY: charge_mixing
      15              :    USE qs_density_mixing_types, ONLY: broyden_mixing_nr, &
      16              :                                       mixing_storage_release, &
      17              :                                       mixing_storage_type
      18              : #if defined(__TBLITE)
      19              :    USE mctc_env, ONLY: error_type
      20              :    USE tblite_scf_mixer_type, ONLY: mixer_type
      21              :    USE tblite_scc_mixer, ONLY: new_cp2k_tblite_mixer
      22              : #endif
      23              : 
      24              :    IMPLICIT NONE
      25              : 
      26              :    REAL(KIND=dp), DIMENSION(1, 1) :: charges
      27              :    TYPE(mp_para_env_type), POINTER :: para_env
      28              :    TYPE(mixing_storage_type), POINTER :: mixing_store
      29              : 
      30            2 :    NULLIFY (mixing_store, para_env)
      31            2 :    ALLOCATE (para_env)
      32            2 :    CALL mp_world_init(para_env)
      33              : 
      34            8 :    ALLOCATE (mixing_store)
      35            2 :    mixing_store%ncall = 0
      36            2 :    mixing_store%nbuffer = 4
      37            2 :    mixing_store%n_simple_mix = 0
      38            2 :    mixing_store%nskip_mixing = 0
      39            2 :    mixing_store%alpha = 0.1_dp
      40            2 :    mixing_store%broy_w0 = 0.01_dp
      41            2 :    mixing_store%nat_local = 1
      42            2 :    mixing_store%max_shell = 1
      43              :    ALLOCATE (mixing_store%acharge(1, 1, 4), mixing_store%dacharge(1, 1, 4), &
      44              :              mixing_store%dfbroy(1, 1, 4), mixing_store%ubroy(1, 1, 4), &
      45            2 :              mixing_store%abroy(4, 4), mixing_store%wbroy(4), mixing_store%atlist(1))
      46           26 :    mixing_store%acharge = 0.0_dp
      47           26 :    mixing_store%dacharge = 0.0_dp
      48           26 :    mixing_store%dfbroy = 0.0_dp
      49           26 :    mixing_store%ubroy = 0.0_dp
      50           42 :    mixing_store%abroy = 0.0_dp
      51           10 :    mixing_store%wbroy = 0.0_dp
      52            4 :    mixing_store%atlist = 1
      53              : 
      54            6 :    charges = 1.0_dp
      55            2 :    CALL charge_mixing(broyden_mixing_nr, mixing_store, charges, para_env, 1)
      56            6 :    charges = 0.5_dp
      57            2 :    CALL charge_mixing(broyden_mixing_nr, mixing_store, charges, para_env, 2)
      58              : 
      59              :    ! Reproduce a degenerate Broyden history by supplying the previous residual again.
      60            2 :    charges(1, 1) = mixing_store%acharge(1, 1, 2) - mixing_store%dacharge(1, 1, 1)
      61            2 :    CALL charge_mixing(broyden_mixing_nr, mixing_store, charges, para_env, 3)
      62              : 
      63            6 :    IF (.NOT. ALL(ieee_is_finite(charges))) THEN
      64            0 :       ERROR STOP "Broyden mixing produced non-finite charges for identical residuals"
      65              :    END IF
      66            6 :    IF (.NOT. ALL(mixing_store%dfbroy(:, :, 1) == 0.0_dp)) THEN
      67            0 :       ERROR STOP "Degenerate Broyden direction was not discarded"
      68              :    END IF
      69              : 
      70            2 :    CALL mixing_storage_release(mixing_store)
      71            2 :    DEALLOCATE (mixing_store)
      72              : #if defined(__TBLITE)
      73            2 :    CALL test_tblite_history()
      74              : #endif
      75            2 :    DEALLOCATE (para_env)
      76            2 :    CALL mp_world_finalize()
      77              : 
      78              : #if defined(__TBLITE)
      79              : CONTAINS
      80              : 
      81              : ! **************************************************************************************************
      82              : !> \brief A wrapped Broyden history must match a fresh replay of the retained input/output pairs.
      83              : ! **************************************************************************************************
      84            2 :    SUBROUTINE test_tblite_history()
      85              :       INTEGER, PARAMETER                                 :: nstep = 16, nvar = 4
      86              : 
      87              :       INTEGER                                            :: config, i, j, memory, step
      88              :       REAL(KIND=dp)                                      :: damping, max_weight, min_weight, omega0, &
      89              :                                                             weight_factor
      90              :       REAL(KIND=dp), DIMENSION(nvar)                     :: actual, expected
      91              :       REAL(KIND=dp), DIMENSION(nvar, nstep)              :: qin, qout
      92              : 
      93            6 :       CLASS(mixer_type), ALLOCATABLE                    :: mixer, replay
      94            2 :       TYPE(error_type), ALLOCATABLE                      :: error
      95              : 
      96           34 :       DO step = 1, nstep
      97          162 :          DO i = 1, nvar
      98          128 :             qin(i, step) = SIN(0.37_dp*REAL(i*step, dp))
      99          160 :             qout(i, step) = qin(i, step) + 0.05_dp*COS(0.21_dp*REAL(i + 2*step, dp))
     100              :          END DO
     101              :       END DO
     102            6 :       DO config = 1, 2
     103            4 :          damping = 0.4_dp
     104            4 :          omega0 = 0.01_dp
     105            4 :          min_weight = 1.0_dp
     106            4 :          max_weight = 100000.0_dp
     107            4 :          weight_factor = 0.01_dp
     108            4 :          IF (config == 2) THEN
     109            2 :             damping = 0.25_dp
     110            2 :             omega0 = 0.1_dp
     111            2 :             min_weight = 0.5_dp
     112            2 :             max_weight = 3.0_dp
     113            2 :             weight_factor = 0.2_dp
     114              :          END IF
     115           22 :          DO memory = 1, 4
     116           30 :             CALL new_cp2k_tblite_mixer(mixer, memory, nvar, damping, omega0, min_weight, max_weight, weight_factor)
     117          276 :             DO step = 1, nstep
     118          256 :                CALL mixer%set(qin(:, step))
     119          256 :                CALL mixer%diff(qout(:, step))
     120          256 :                CALL mixer%next(error)
     121          256 :                IF (ALLOCATED(error)) ERROR STOP "Wrapped tblite mixer failed"
     122          256 :                CALL mixer%get(actual)
     123              : 
     124              :                ! Replay at most memory + 1 pairs: this builds exactly the retained
     125              :                ! secant directions without ever overwriting a history slot.
     126          510 :                CALL new_cp2k_tblite_mixer(replay, memory, nvar, damping, omega0, min_weight, max_weight, weight_factor)
     127         1072 :                DO j = MAX(1, step - memory), step
     128          816 :                   CALL replay%set(qin(:, j))
     129          816 :                   CALL replay%diff(qout(:, j))
     130          816 :                   CALL replay%next(error)
     131         1072 :                   IF (ALLOCATED(error)) ERROR STOP "Replayed tblite mixer failed"
     132              :                END DO
     133          256 :                CALL replay%get(expected)
     134         1280 :                IF (.NOT. ALL(ieee_is_finite(actual))) ERROR STOP "Non-finite wrapped tblite history"
     135         1296 :                IF (MAXVAL(ABS(actual - expected)) > 1.0E-10_dp) THEN
     136            0 :                   ERROR STOP "Wrapped tblite history differs from an unwrapped replay"
     137              :                END IF
     138              :             END DO
     139              :          END DO
     140              :       END DO
     141              : 
     142            4 :    END SUBROUTINE test_tblite_history
     143              : #endif
     144              : 
     145              : END PROGRAM qs_charge_mixing_unittest
     146              : ! vim: set ts=3 sw=3 tw=132 :
        

Generated by: LCOV version 2.0-1