LCOV - code coverage report
Current view: top level - src - qs_tddfpt2_eigensolver.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4dc10b3) Lines: 273 285 95.8 %
Date: 2024-11-21 06:45:46 Functions: 7 7 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : MODULE qs_tddfpt2_eigensolver
       9             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      10             :    USE cp_control_types,                ONLY: tddfpt2_control_type
      11             :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      12             :                                               dbcsr_p_type,&
      13             :                                               dbcsr_type
      14             :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      15             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_contracted_trace,&
      16             :                                               cp_fm_scale,&
      17             :                                               cp_fm_scale_and_add,&
      18             :                                               cp_fm_trace
      19             :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      20             :    USE cp_fm_pool_types,                ONLY: fm_pool_create_fm,&
      21             :                                               fm_pool_give_back_fm
      22             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      23             :                                               cp_fm_struct_release,&
      24             :                                               cp_fm_struct_type
      25             :    USE cp_fm_types,                     ONLY: &
      26             :         cp_fm_copy_general, cp_fm_create, cp_fm_get_info, cp_fm_get_submatrix, cp_fm_maxabsval, &
      27             :         cp_fm_release, cp_fm_set_all, cp_fm_set_submatrix, cp_fm_to_fm, cp_fm_type
      28             :    USE cp_log_handling,                 ONLY: cp_logger_type
      29             :    USE cp_output_handling,              ONLY: cp_iterate
      30             :    USE input_constants,                 ONLY: tddfpt_kernel_full,&
      31             :                                               tddfpt_kernel_none,&
      32             :                                               tddfpt_kernel_stda
      33             :    USE input_section_types,             ONLY: section_vals_type
      34             :    USE kinds,                           ONLY: dp,&
      35             :                                               int_8
      36             :    USE machine,                         ONLY: m_flush,&
      37             :                                               m_walltime
      38             :    USE memory_utilities,                ONLY: reallocate
      39             :    USE message_passing,                 ONLY: mp_para_env_type
      40             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      41             :    USE physcon,                         ONLY: evolt
      42             :    USE qs_environment_types,            ONLY: get_qs_env,&
      43             :                                               qs_environment_type
      44             :    USE qs_kernel_types,                 ONLY: full_kernel_env_type,&
      45             :                                               kernel_env_type
      46             :    USE qs_scf_methods,                  ONLY: eigensolver
      47             :    USE qs_tddfpt2_fhxc,                 ONLY: fhxc_kernel,&
      48             :                                               stda_kernel
      49             :    USE qs_tddfpt2_operators,            ONLY: tddfpt_apply_energy_diff,&
      50             :                                               tddfpt_apply_hfx,&
      51             :                                               tddfpt_apply_hfxlr_kernel,&
      52             :                                               tddfpt_apply_hfxsr_kernel
      53             :    USE qs_tddfpt2_restart,              ONLY: tddfpt_write_restart
      54             :    USE qs_tddfpt2_subgroups,            ONLY: tddfpt_subgroup_env_type
      55             :    USE qs_tddfpt2_types,                ONLY: tddfpt_ground_state_mos,&
      56             :                                               tddfpt_work_matrices
      57             :    USE qs_tddfpt2_utils,                ONLY: tddfpt_total_number_of_states
      58             : #include "./base/base_uses.f90"
      59             : 
      60             :    IMPLICIT NONE
      61             : 
      62             :    PRIVATE
      63             : 
      64             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_eigensolver'
      65             : 
      66             :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      67             :    ! number of first derivative components (3: d/dx, d/dy, d/dz)
      68             :    INTEGER, PARAMETER, PRIVATE          :: nderivs = 3
      69             :    INTEGER, PARAMETER, PRIVATE          :: maxspins = 2
      70             : 
      71             :    PUBLIC :: tddfpt_davidson_solver, tddfpt_orthogonalize_psi1_psi0, &
      72             :              tddfpt_orthonormalize_psi1_psi1
      73             : 
      74             : ! **************************************************************************************************
      75             : 
      76             : CONTAINS
      77             : 
      78             : ! **************************************************************************************************
      79             : !> \brief Make TDDFPT trial vectors orthogonal to all occupied molecular orbitals.
      80             : !> \param evects            trial vectors distributed across all processors (modified on exit)
      81             : !> \param S_C0_C0T          matrix product S * C_0 * C_0^T, where C_0 is the ground state
      82             : !>                          wave function for each spin expressed in atomic basis set,
      83             : !>                          and S is the corresponding overlap matrix
      84             : !> \par History
      85             : !>    * 05.2016 created [Sergey Chulkov]
      86             : !>    * 05.2019 use a temporary work matrix [JHU]
      87             : !> \note  Based on the subroutine p_preortho() which was created by Thomas Chassaing on 09.2002.
      88             : !>        Should be useless when ground state MOs are computed with extremely high accuracy,
      89             : !>        as all virtual orbitals are already orthogonal to the occupied ones by design.
      90             : !>        However, when the norm of residual vectors is relatively small (e.g. less then SCF_EPS),
      91             : !>        new Krylov's vectors seem to be random and should be orthogonalised even with respect to
      92             : !>        the occupied MOs.
      93             : ! **************************************************************************************************
      94        7088 :    SUBROUTINE tddfpt_orthogonalize_psi1_psi0(evects, S_C0_C0T)
      95             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
      96             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(in)         :: S_C0_C0T
      97             : 
      98             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_orthogonalize_psi1_psi0'
      99             : 
     100             :       INTEGER                                            :: handle, ispin, ivect, nactive, nao, &
     101             :                                                             nspins, nvects
     102             :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
     103             :       TYPE(cp_fm_type)                                   :: evortho
     104             : 
     105        7088 :       CALL timeset(routineN, handle)
     106             : 
     107        7088 :       nspins = SIZE(evects, 1)
     108        7088 :       nvects = SIZE(evects, 2)
     109             : 
     110        7088 :       IF (nvects > 0) THEN
     111       15066 :          DO ispin = 1, nspins
     112             :             CALL cp_fm_get_info(matrix=evects(ispin, 1), matrix_struct=matrix_struct, &
     113        7978 :                                 nrow_global=nao, ncol_global=nactive)
     114        7978 :             CALL cp_fm_create(evortho, matrix_struct)
     115       28646 :             DO ivect = 1, nvects
     116             :                ! evortho: C0 * C0^T * S * C1 == (S * C0 * C0^T)^T * C1
     117             :                CALL parallel_gemm('T', 'N', nao, nactive, nao, 1.0_dp, S_C0_C0T(ispin), &
     118       20668 :                                   evects(ispin, ivect), 0.0_dp, evortho)
     119       28646 :                CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, ivect), -1.0_dp, evortho)
     120             :             END DO
     121       23044 :             CALL cp_fm_release(evortho)
     122             :          END DO
     123             :       END IF
     124             : 
     125        7088 :       CALL timestop(handle)
     126             : 
     127        7088 :    END SUBROUTINE tddfpt_orthogonalize_psi1_psi0
     128             : 
     129             : ! **************************************************************************************************
     130             : !> \brief Check that orthogonalised TDDFPT trial vectors remain orthogonal to
     131             : !>        occupied molecular orbitals.
     132             : !> \param evects    trial vectors
     133             : !> \param S_C0      matrix product S * C_0, where C_0 is the ground state wave function
     134             : !>                  for each spin in atomic basis set, and S is the corresponding overlap matrix
     135             : !> \param max_norm  the largest possible overlap between the ground state and
     136             : !>                  excited state wave functions
     137             : !> \return true if trial vectors are non-orthogonal to occupied molecular orbitals
     138             : !> \par History
     139             : !>    * 07.2016 created [Sergey Chulkov]
     140             : !>    * 05.2019 use temporary work matrices [JHU]
     141             : ! **************************************************************************************************
     142        3904 :    FUNCTION tddfpt_is_nonorthogonal_psi1_psi0(evects, S_C0, max_norm) &
     143             :       RESULT(is_nonortho)
     144             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
     145             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(in)         :: S_C0
     146             :       REAL(kind=dp), INTENT(in)                          :: max_norm
     147             :       LOGICAL                                            :: is_nonortho
     148             : 
     149             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_is_nonorthogonal_psi1_psi0'
     150             : 
     151             :       INTEGER                                            :: handle, ispin, ivect, nactive, nao, &
     152             :                                                             nocc, nspins, nvects
     153             :       REAL(kind=dp)                                      :: maxabs_val
     154             :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct, matrix_struct_tmp
     155             :       TYPE(cp_fm_type)                                   :: aortho
     156             : 
     157        3904 :       CALL timeset(routineN, handle)
     158             : 
     159        3904 :       nspins = SIZE(evects, 1)
     160        3904 :       nvects = SIZE(evects, 2)
     161             : 
     162        3904 :       is_nonortho = .FALSE.
     163             : 
     164        8322 :       loop: DO ispin = 1, nspins
     165        4424 :          CALL cp_fm_get_info(matrix=S_C0(ispin), ncol_global=nocc)
     166             :          CALL cp_fm_get_info(matrix=evects(ispin, 1), matrix_struct=matrix_struct, &
     167        4424 :                              nrow_global=nao, ncol_global=nactive)
     168             :          CALL cp_fm_struct_create(matrix_struct_tmp, nrow_global=nocc, &
     169        4424 :                                   ncol_global=nactive, template_fmstruct=matrix_struct)
     170        4424 :          CALL cp_fm_create(aortho, matrix_struct_tmp)
     171        4424 :          CALL cp_fm_struct_release(matrix_struct_tmp)
     172       15328 :          DO ivect = 1, nvects
     173             :             ! aortho = S_0^T * S * C_1
     174             :             CALL parallel_gemm('T', 'N', nocc, nactive, nao, 1.0_dp, S_C0(ispin), &
     175       10910 :                                evects(ispin, ivect), 0.0_dp, aortho)
     176       10910 :             CALL cp_fm_maxabsval(aortho, maxabs_val)
     177       10910 :             is_nonortho = maxabs_val > max_norm
     178       15328 :             IF (is_nonortho) THEN
     179           6 :                CALL cp_fm_release(aortho)
     180           6 :                EXIT loop
     181             :             END IF
     182             :          END DO
     183       17164 :          CALL cp_fm_release(aortho)
     184             :       END DO loop
     185             : 
     186        3904 :       CALL timestop(handle)
     187             : 
     188        3904 :    END FUNCTION tddfpt_is_nonorthogonal_psi1_psi0
     189             : 
     190             : ! **************************************************************************************************
     191             : !> \brief Make new TDDFPT trial vectors orthonormal to all previous trial vectors.
     192             : !> \param evects      trial vectors (modified on exit)
     193             : !> \param nvects_new  number of new trial vectors to orthogonalise
     194             : !> \param S_evects    set of matrices to store matrix product S * evects (modified on exit)
     195             : !> \param matrix_s    overlap matrix
     196             : !> \par History
     197             : !>    * 05.2016 created [Sergey Chulkov]
     198             : !>    * 02.2017 caching the matrix product S * evects [Sergey Chulkov]
     199             : !> \note \parblock
     200             : !>       Based on the subroutines reorthogonalize() and normalize() which were originally created
     201             : !>       by Thomas Chassaing on 03.2003.
     202             : !>
     203             : !>       In order to orthogonalise a trial vector C3 = evects(:,3) with respect to previously
     204             : !>       orthogonalised vectors C1 = evects(:,1) and C2 = evects(:,2) we need to compute the
     205             : !>       quantity C3'' using the following formulae:
     206             : !>          C3'  = C3  - Tr(C3^T  * S * C1) * C1,
     207             : !>          C3'' = C3' - Tr(C3'^T * S * C2) * C2,
     208             : !>       which can be expanded as:
     209             : !>          C3'' = C3 - Tr(C3^T  * S * C1) * C1 - Tr(C3^T * S * C2) * C2 +
     210             : !>                 Tr(C3^T * S * C1) * Tr(C2^T * S * C1) * C2 .
     211             : !>       In case of unlimited float-point precision, the last term in above expression is exactly 0,
     212             : !>       due to orthogonality condition between C1 and C2. In this case the expression could be
     213             : !>       simplified as (taking into account the identity: Tr(A * S * B) = Tr(B * S * A)):
     214             : !>          C3'' = C3 - Tr(C1^T  * S * C3) * C1 - Tr(C2^T * S * C3) * C2 ,
     215             : !>       which means we do not need the variable S_evects to keep the matrix products S * Ci .
     216             : !>
     217             : !>       In reality, however, we deal with limited float-point precision arithmetic meaning that
     218             : !>       the trace Tr(C2^T * S * C1) is close to 0 but does not equal to 0 exactly. The term
     219             : !>          Tr(C3^T * S * C1) * Tr(C2^T * S * C1) * C2
     220             : !>       can not be ignored anymore. Ignorance of this term will lead to numerical instability
     221             : !>       when the trace Tr(C3^T * S * C1) is large enough.
     222             : !>       \endparblock
     223             : ! **************************************************************************************************
     224        7088 :    SUBROUTINE tddfpt_orthonormalize_psi1_psi1(evects, nvects_new, S_evects, matrix_s)
     225             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
     226             :       INTEGER, INTENT(in)                                :: nvects_new
     227             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: S_evects
     228             :       TYPE(dbcsr_type), POINTER                          :: matrix_s
     229             : 
     230             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_orthonormalize_psi1_psi1'
     231             : 
     232             :       INTEGER                                            :: handle, ispin, ivect, jvect, nspins, &
     233             :                                                             nvects_old, nvects_total
     234             :       INTEGER, DIMENSION(maxspins)                       :: nactive
     235             :       REAL(kind=dp)                                      :: norm
     236             :       REAL(kind=dp), DIMENSION(maxspins)                 :: weights
     237             : 
     238        7088 :       CALL timeset(routineN, handle)
     239             : 
     240        7088 :       nspins = SIZE(evects, 1)
     241        7088 :       nvects_total = SIZE(evects, 2)
     242        7088 :       nvects_old = nvects_total - nvects_new
     243             : 
     244             :       IF (debug_this_module) THEN
     245             :          CPASSERT(SIZE(S_evects, 1) == nspins)
     246             :          CPASSERT(SIZE(S_evects, 2) == nvects_total)
     247             :          CPASSERT(nvects_old >= 0)
     248             :       END IF
     249             : 
     250       15066 :       DO ispin = 1, nspins
     251       15066 :          CALL cp_fm_get_info(matrix=evects(ispin, 1), ncol_global=nactive(ispin))
     252             :       END DO
     253             : 
     254       25102 :       DO jvect = nvects_old + 1, nvects_total
     255             :          ! <psi1_i | psi1_j>
     256      138648 :          DO ivect = 1, jvect - 1
     257      120634 :             CALL cp_fm_trace(evects(:, jvect), S_evects(:, ivect), weights(1:nspins), accurate=.FALSE.)
     258      260854 :             norm = SUM(weights(1:nspins))
     259             : 
     260      278868 :             DO ispin = 1, nspins
     261      260854 :                CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, jvect), -norm, evects(ispin, ivect))
     262             :             END DO
     263             :          END DO
     264             : 
     265             :          ! <psi1_j | psi1_j>
     266       38682 :          DO ispin = 1, nspins
     267             :             CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, jvect), S_evects(ispin, jvect), &
     268       38682 :                                          ncol=nactive(ispin), alpha=1.0_dp, beta=0.0_dp)
     269             :          END DO
     270             : 
     271       18014 :          CALL cp_fm_trace(evects(:, jvect), S_evects(:, jvect), weights(1:nspins), accurate=.FALSE.)
     272             : 
     273       38682 :          norm = SUM(weights(1:nspins))
     274       18014 :          norm = 1.0_dp/SQRT(norm)
     275             : 
     276       45770 :          DO ispin = 1, nspins
     277       20668 :             CALL cp_fm_scale(norm, evects(ispin, jvect))
     278       38682 :             CALL cp_fm_scale(norm, S_evects(ispin, jvect))
     279             :          END DO
     280             :       END DO
     281             : 
     282        7088 :       CALL timestop(handle)
     283             : 
     284        7088 :    END SUBROUTINE tddfpt_orthonormalize_psi1_psi1
     285             : 
     286             : ! **************************************************************************************************
     287             : !> \brief Compute action matrix-vector products.
     288             : !> \param Aop_evects            action of TDDFPT operator on trial vectors (modified on exit)
     289             : !> \param evects                TDDFPT trial vectors
     290             : !> \param S_evects              cached matrix product S * evects where S is the overlap matrix
     291             : !>                              in primary basis set
     292             : !> \param gs_mos                molecular orbitals optimised for the ground state
     293             : !> \param tddfpt_control        control section for tddfpt
     294             : !> \param matrix_ks             Kohn-Sham matrix
     295             : !> \param qs_env                Quickstep environment
     296             : !> \param kernel_env            kernel environment
     297             : !> \param sub_env               parallel (sub)group environment
     298             : !> \param work_matrices         collection of work matrices (modified on exit)
     299             : !> \par History
     300             : !>    * 06.2016 created [Sergey Chulkov]
     301             : !>    * 03.2017 refactored [Sergey Chulkov]
     302             : ! **************************************************************************************************
     303        6020 :    SUBROUTINE tddfpt_compute_Aop_evects(Aop_evects, evects, S_evects, gs_mos, tddfpt_control, &
     304        6020 :                                         matrix_ks, qs_env, kernel_env, &
     305             :                                         sub_env, work_matrices)
     306             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: Aop_evects, evects, S_evects
     307             :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     308             :          INTENT(in)                                      :: gs_mos
     309             :       TYPE(tddfpt2_control_type), POINTER                :: tddfpt_control
     310             :       TYPE(dbcsr_p_type), DIMENSION(:), INTENT(in)       :: matrix_ks
     311             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     312             :       TYPE(kernel_env_type), INTENT(in)                  :: kernel_env
     313             :       TYPE(tddfpt_subgroup_env_type), INTENT(in)         :: sub_env
     314             :       TYPE(tddfpt_work_matrices), INTENT(inout)          :: work_matrices
     315             : 
     316             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_Aop_evects'
     317             : 
     318             :       INTEGER                                            :: handle, ispin, ivect, nspins, nvects
     319             :       INTEGER, DIMENSION(maxspins)                       :: nmo_occ
     320             :       LOGICAL                                            :: do_admm, do_hfx, do_lri_response, &
     321             :                                                             is_rks_triplets, re_int
     322             :       REAL(KIND=dp)                                      :: rcut, scale
     323             :       TYPE(cp_fm_type)                                   :: fm_dummy
     324             :       TYPE(full_kernel_env_type), POINTER                :: kernel_env_admm_aux
     325             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     326             : 
     327        6020 :       CALL timeset(routineN, handle)
     328             : 
     329        6020 :       nspins = SIZE(evects, 1)
     330        6020 :       nvects = SIZE(evects, 2)
     331        6020 :       do_hfx = tddfpt_control%do_hfx
     332        6020 :       do_admm = tddfpt_control%do_admm
     333        6020 :       IF (do_admm) THEN
     334         716 :          kernel_env_admm_aux => kernel_env%admm_kernel
     335             :       ELSE
     336        5304 :          NULLIFY (kernel_env_admm_aux)
     337             :       END IF
     338        6020 :       is_rks_triplets = tddfpt_control%rks_triplets
     339        6020 :       do_lri_response = tddfpt_control%do_lrigpw
     340             : 
     341             :       IF (debug_this_module) THEN
     342             :          CPASSERT(nspins > 0)
     343             :          CPASSERT(SIZE(Aop_evects, 1) == nspins)
     344             :          CPASSERT(SIZE(Aop_evects, 2) == nvects)
     345             :          CPASSERT(SIZE(S_evects, 1) == nspins)
     346             :          CPASSERT(SIZE(S_evects, 2) == nvects)
     347             :          CPASSERT(SIZE(gs_mos) == nspins)
     348             :       END IF
     349             : 
     350       12806 :       DO ispin = 1, nspins
     351        6020 :          nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
     352             :       END DO
     353             : 
     354        6020 :       IF (nvects > 0) THEN
     355        6020 :          CALL cp_fm_get_info(evects(1, 1), para_env=para_env)
     356        6020 :          IF (ALLOCATED(work_matrices%evects_sub)) THEN
     357          30 :             DO ivect = 1, nvects
     358          50 :                DO ispin = 1, nspins
     359          20 :                   ASSOCIATE (evect => evects(ispin, ivect), work_matrix => work_matrices%evects_sub(ispin, ivect))
     360          20 :                   IF (ASSOCIATED(evect%matrix_struct)) THEN
     361          20 :                   IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
     362          10 :                      CALL cp_fm_copy_general(evect, work_matrix, para_env)
     363             :                   ELSE
     364          10 :                      CALL cp_fm_copy_general(evect, fm_dummy, para_env)
     365             :                   END IF
     366           0 :                   ELSE IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
     367           0 :                   CALL cp_fm_copy_general(fm_dummy, work_matrix, para_env)
     368             :                   ELSE
     369           0 :                   CALL cp_fm_copy_general(fm_dummy, fm_dummy, para_env)
     370             :                   END IF
     371             :                   END ASSOCIATE
     372             :                END DO
     373             :             END DO
     374             :          END IF
     375             : 
     376        6020 :          IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
     377             :             ! full TDDFPT kernel
     378             :             CALL fhxc_kernel(Aop_evects, evects, is_rks_triplets, do_hfx, do_admm, qs_env, &
     379             :                              kernel_env%full_kernel, kernel_env_admm_aux, sub_env, work_matrices, &
     380             :                              tddfpt_control%admm_symm, tddfpt_control%admm_xc_correction, &
     381        3318 :                              do_lri_response)
     382        2702 :          ELSE IF (tddfpt_control%kernel == tddfpt_kernel_stda) THEN
     383             :             ! sTDA kernel
     384             :             CALL stda_kernel(Aop_evects, evects, is_rks_triplets, qs_env, tddfpt_control%stda_control, &
     385        2514 :                              kernel_env%stda_kernel, sub_env, work_matrices)
     386         188 :          ELSE IF (tddfpt_control%kernel == tddfpt_kernel_none) THEN
     387             :             ! No kernel
     388         680 :             DO ivect = 1, nvects
     389        1172 :                DO ispin = 1, nspins
     390         984 :                   CALL cp_fm_set_all(Aop_evects(ispin, ivect), 0.0_dp)
     391             :                END DO
     392             :             END DO
     393             :          ELSE
     394           0 :             CPABORT("Kernel type not implemented")
     395             :          END IF
     396             : 
     397        6020 :          IF (ALLOCATED(work_matrices%evects_sub)) THEN
     398          30 :             DO ivect = 1, nvects
     399          50 :                DO ispin = 1, nspins
     400             :                   ASSOCIATE (Aop_evect => Aop_evects(ispin, ivect), &
     401          20 :                              work_matrix => work_matrices%Aop_evects_sub(ispin, ivect))
     402          20 :                   IF (ASSOCIATED(Aop_evect%matrix_struct)) THEN
     403          20 :                   IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
     404          10 :                      CALL cp_fm_copy_general(work_matrix, Aop_evect, para_env)
     405             :                   ELSE
     406          10 :                      CALL cp_fm_copy_general(fm_dummy, Aop_evect, para_env)
     407             :                   END IF
     408           0 :                   ELSE IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
     409           0 :                   CALL cp_fm_copy_general(work_matrix, fm_dummy, para_env)
     410             :                   ELSE
     411           0 :                   CALL cp_fm_copy_general(fm_dummy, fm_dummy, para_env)
     412             :                   END IF
     413             :                   END ASSOCIATE
     414             :                END DO
     415             :             END DO
     416             :          END IF
     417             : 
     418             :          ! orbital energy difference term
     419             :          CALL tddfpt_apply_energy_diff(Aop_evects=Aop_evects, evects=evects, S_evects=S_evects, &
     420        6020 :                                        gs_mos=gs_mos, matrix_ks=matrix_ks)
     421             : 
     422        6020 :          IF (do_hfx) THEN
     423        1304 :             IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
     424             :                ! full TDDFPT kernel
     425             :                CALL tddfpt_apply_hfx(Aop_evects=Aop_evects, evects=evects, gs_mos=gs_mos, do_admm=do_admm, &
     426             :                                      qs_env=qs_env, wfm_rho_orb=work_matrices%hfx_fm_ao_ao, &
     427             :                                      work_hmat_symm=work_matrices%hfx_hmat_symm, &
     428             :                                      work_hmat_asymm=work_matrices%hfx_hmat_asymm, &
     429             :                                      work_rho_ia_ao_symm=work_matrices%hfx_rho_ao_symm, &
     430        1304 :                                      work_rho_ia_ao_asymm=work_matrices%hfx_rho_ao_asymm)
     431           0 :             ELSE IF (tddfpt_control%kernel == tddfpt_kernel_stda) THEN
     432             :                ! sTDA kernel
     433             :                ! special treatment of HFX term
     434           0 :             ELSE IF (tddfpt_control%kernel == tddfpt_kernel_none) THEN
     435             :                ! No kernel
     436             :                ! drop kernel contribution of HFX term
     437             :             ELSE
     438           0 :                CPABORT("Kernel type not implemented")
     439             :             END IF
     440             :          END IF
     441             :          ! short/long range HFX
     442        6020 :          IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
     443        3318 :             IF (tddfpt_control%do_hfxsr) THEN
     444          26 :                re_int = tddfpt_control%hfxsr_re_int
     445             :                ! symmetric dmat
     446             :                CALL tddfpt_apply_hfxsr_kernel(Aop_evects, evects, gs_mos, qs_env, &
     447             :                                               kernel_env%full_kernel%admm_env, &
     448             :                                               kernel_env%full_kernel%hfxsr_section, &
     449             :                                               kernel_env%full_kernel%x_data, 1, re_int, &
     450             :                                               work_rho_ia_ao=work_matrices%hfxsr_rho_ao_symm, &
     451             :                                               work_hmat=work_matrices%hfxsr_hmat_symm, &
     452          26 :                                               wfm_rho_orb=work_matrices%hfxsr_fm_ao_ao)
     453             :                ! antisymmetric dmat
     454             :                CALL tddfpt_apply_hfxsr_kernel(Aop_evects, evects, gs_mos, qs_env, &
     455             :                                               kernel_env%full_kernel%admm_env, &
     456             :                                               kernel_env%full_kernel%hfxsr_section, &
     457             :                                               kernel_env%full_kernel%x_data, -1, .FALSE., &
     458             :                                               work_rho_ia_ao=work_matrices%hfxsr_rho_ao_asymm, &
     459             :                                               work_hmat=work_matrices%hfxsr_hmat_asymm, &
     460          26 :                                               wfm_rho_orb=work_matrices%hfxsr_fm_ao_ao)
     461          26 :                tddfpt_control%hfxsr_re_int = .FALSE.
     462             :             END IF
     463        3318 :             IF (tddfpt_control%do_hfxlr) THEN
     464          42 :                rcut = tddfpt_control%hfxlr_rcut
     465          42 :                scale = tddfpt_control%hfxlr_scale
     466         126 :                DO ivect = 1, nvects
     467         126 :                   IF (ALLOCATED(work_matrices%evects_sub)) THEN
     468           0 :                      IF (ASSOCIATED(work_matrices%evects_sub(1, ivect)%matrix_struct)) THEN
     469             :                         CALL tddfpt_apply_hfxlr_kernel(qs_env, sub_env, rcut, scale, work_matrices, &
     470             :                                                        work_matrices%evects_sub(:, ivect), &
     471           0 :                                                        work_matrices%Aop_evects_sub(:, ivect))
     472             :                      ELSE
     473             :                         ! skip trial vectors which are assigned to different parallel groups
     474             :                         CYCLE
     475             :                      END IF
     476             :                   ELSE
     477             :                      CALL tddfpt_apply_hfxlr_kernel(qs_env, sub_env, rcut, scale, work_matrices, &
     478          84 :                                                     evects(:, ivect), Aop_evects(:, ivect))
     479             :                   END IF
     480             :                END DO
     481             :             END IF
     482             :          END IF
     483             : 
     484             :       END IF
     485             : 
     486        6020 :       CALL timestop(handle)
     487             : 
     488        6020 :    END SUBROUTINE tddfpt_compute_Aop_evects
     489             : 
     490             : ! **************************************************************************************************
     491             : !> \brief Solve eigenproblem for the reduced action matrix and find new Ritz eigenvectors and
     492             : !>        eigenvalues.
     493             : !> \param ritz_vects       Ritz eigenvectors (initialised on exit)
     494             : !> \param Aop_ritz         approximate action of TDDFPT operator on Ritz vectors (initialised on exit)
     495             : !> \param evals            Ritz eigenvalues (initialised on exit)
     496             : !> \param krylov_vects     Krylov's vectors
     497             : !> \param Aop_krylov       action of TDDFPT operator on Krylov's vectors
     498             : !> \param Atilde ...
     499             : !> \param nkvo ...
     500             : !> \param nkvn ...
     501             : !> \par History
     502             : !>    * 06.2016 created [Sergey Chulkov]
     503             : !>    * 03.2017 altered prototype, OpenMP parallelisation [Sergey Chulkov]
     504             : ! **************************************************************************************************
     505        6020 :    SUBROUTINE tddfpt_compute_ritz_vects(ritz_vects, Aop_ritz, evals, krylov_vects, Aop_krylov, &
     506             :                                         Atilde, nkvo, nkvn)
     507             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: ritz_vects, Aop_ritz
     508             :       REAL(kind=dp), DIMENSION(:), INTENT(out)           :: evals
     509             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: krylov_vects, Aop_krylov
     510             :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: Atilde
     511             :       INTEGER, INTENT(IN)                                :: nkvo, nkvn
     512             : 
     513             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_ritz_vects'
     514             : 
     515             :       INTEGER                                            :: handle, ikv, irv, ispin, nkvs, nrvs, &
     516             :                                                             nspins
     517             :       REAL(kind=dp)                                      :: act
     518        6020 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: at12, at21, at22, evects_Atilde
     519             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_global
     520             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     521             :       TYPE(cp_fm_type)                                   :: Atilde_fm, evects_Atilde_fm
     522             : 
     523        6020 :       CALL timeset(routineN, handle)
     524             : 
     525        6020 :       nspins = SIZE(krylov_vects, 1)
     526        6020 :       nkvs = SIZE(krylov_vects, 2)
     527        6020 :       nrvs = SIZE(ritz_vects, 2)
     528        6020 :       CPASSERT(nkvs == nkvo + nkvn)
     529             : 
     530        6020 :       CALL cp_fm_get_info(krylov_vects(1, 1), context=blacs_env_global)
     531             : 
     532        6020 :       CALL cp_fm_struct_create(fm_struct, nrow_global=nkvs, ncol_global=nkvs, context=blacs_env_global)
     533        6020 :       CALL cp_fm_create(Atilde_fm, fm_struct)
     534        6020 :       CALL cp_fm_create(evects_Atilde_fm, fm_struct)
     535        6020 :       CALL cp_fm_struct_release(fm_struct)
     536             : 
     537             :       ! *** compute upper-diagonal reduced action matrix ***
     538        6020 :       CALL reallocate(Atilde, 1, nkvs, 1, nkvs)
     539             :       ! TO DO: the subroutine 'cp_fm_contracted_trace' will compute all elements of
     540             :       ! the matrix 'Atilde', however only upper-triangular elements are actually needed
     541             :       !
     542        6020 :       IF (nkvo == 0) THEN
     543             :          CALL cp_fm_contracted_trace(Aop_krylov(:, 1:nkvs), krylov_vects(:, 1:nkvs), &
     544        2122 :                                      Atilde(1:nkvs, 1:nkvs), accurate=.FALSE.)
     545             :       ELSE
     546       35082 :          ALLOCATE (at12(nkvn, nkvo), at21(nkvo, nkvn), at22(nkvn, nkvn))
     547             :          CALL cp_fm_contracted_trace(Aop_krylov(:, nkvo + 1:nkvs), krylov_vects(:, 1:nkvo), &
     548        3898 :                                      at12, accurate=.FALSE.)
     549      129770 :          Atilde(nkvo + 1:nkvs, 1:nkvo) = at12(1:nkvn, 1:nkvo)
     550             :          CALL cp_fm_contracted_trace(Aop_krylov(:, 1:nkvo), krylov_vects(:, nkvo + 1:nkvs), &
     551        3898 :                                      at21, accurate=.FALSE.)
     552      107656 :          Atilde(1:nkvo, nkvo + 1:nkvs) = at21(1:nkvo, 1:nkvn)
     553             :          CALL cp_fm_contracted_trace(Aop_krylov(:, nkvo + 1:nkvs), krylov_vects(:, nkvo + 1:nkvs), &
     554        3898 :                                      at22, accurate=.FALSE.)
     555       47830 :          Atilde(nkvo + 1:nkvs, nkvo + 1:nkvs) = at22(1:nkvn, 1:nkvn)
     556        3898 :          DEALLOCATE (at12, at21, at22)
     557             :       END IF
     558     1559360 :       Atilde = 0.5_dp*(Atilde + TRANSPOSE(Atilde))
     559        6020 :       CALL cp_fm_set_submatrix(Atilde_fm, Atilde)
     560             : 
     561             :       ! *** solve an eigenproblem for the reduced matrix ***
     562        6020 :       CALL choose_eigv_solver(Atilde_fm, evects_Atilde_fm, evals(1:nkvs))
     563             : 
     564       24080 :       ALLOCATE (evects_Atilde(nkvs, nrvs))
     565        6020 :       CALL cp_fm_get_submatrix(evects_Atilde_fm, evects_Atilde, start_row=1, start_col=1, n_rows=nkvs, n_cols=nrvs)
     566        6020 :       CALL cp_fm_release(evects_Atilde_fm)
     567        6020 :       CALL cp_fm_release(Atilde_fm)
     568             : 
     569             : !$OMP PARALLEL DO DEFAULT(NONE), &
     570             : !$OMP             PRIVATE(act, ikv, irv, ispin), &
     571        6020 : !$OMP             SHARED(Aop_krylov, Aop_ritz, krylov_vects, evects_Atilde, nkvs, nrvs, nspins, ritz_vects)
     572             :       DO irv = 1, nrvs
     573             :          DO ispin = 1, nspins
     574             :             CALL cp_fm_set_all(ritz_vects(ispin, irv), 0.0_dp)
     575             :             CALL cp_fm_set_all(Aop_ritz(ispin, irv), 0.0_dp)
     576             :          END DO
     577             : 
     578             :          DO ikv = 1, nkvs
     579             :             act = evects_Atilde(ikv, irv)
     580             :             DO ispin = 1, nspins
     581             :                CALL cp_fm_scale_and_add(1.0_dp, ritz_vects(ispin, irv), &
     582             :                                         act, krylov_vects(ispin, ikv))
     583             :                CALL cp_fm_scale_and_add(1.0_dp, Aop_ritz(ispin, irv), &
     584             :                                         act, Aop_krylov(ispin, ikv))
     585             :             END DO
     586             :          END DO
     587             :       END DO
     588             : !$OMP END PARALLEL DO
     589             : 
     590        6020 :       DEALLOCATE (evects_Atilde)
     591             : 
     592        6020 :       CALL timestop(handle)
     593             : 
     594       18060 :    END SUBROUTINE tddfpt_compute_ritz_vects
     595             : 
     596             : ! **************************************************************************************************
     597             : !> \brief Expand Krylov space by computing residual vectors.
     598             : !> \param residual_vects          residual vectors (modified on exit)
     599             : !> \param evals                   Ritz eigenvalues (modified on exit)
     600             : !> \param ritz_vects              Ritz eigenvectors
     601             : !> \param Aop_ritz                approximate action of TDDFPT operator on Ritz vectors
     602             : !> \param gs_mos                  molecular orbitals optimised for the ground state
     603             : !> \param matrix_s                overlap matrix
     604             : !> \par History
     605             : !>    * 06.2016 created [Sergey Chulkov]
     606             : !>    * 03.2017 refactored to achieve significant performance gain [Sergey Chulkov]
     607             : ! **************************************************************************************************
     608        3904 :    SUBROUTINE tddfpt_compute_residual_vects(residual_vects, evals, ritz_vects, Aop_ritz, gs_mos, &
     609             :                                             matrix_s)
     610             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: residual_vects
     611             :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: evals
     612             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: ritz_vects, Aop_ritz
     613             :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     614             :          INTENT(in)                                      :: gs_mos
     615             :       TYPE(dbcsr_type), POINTER                          :: matrix_s
     616             : 
     617             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_residual_vects'
     618             :       REAL(kind=dp), PARAMETER :: eref_scale = 0.99_dp, threshold = 16.0_dp*EPSILON(1.0_dp)
     619             : 
     620             :       INTEGER                                            :: handle, icol_local, irow_local, irv, &
     621             :                                                             ispin, nao, ncols_local, nrows_local, &
     622             :                                                             nrvs, nspins
     623        3904 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices_local, row_indices_local
     624             :       INTEGER, DIMENSION(maxspins)                       :: nactive, nmo_virt
     625             :       REAL(kind=dp)                                      :: e_occ_plus_lambda, eref, lambda
     626             :       REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
     627        3904 :          POINTER                                         :: weights_ldata
     628             :       TYPE(cp_fm_struct_type), POINTER                   :: ao_mo_struct, virt_mo_struct
     629        3904 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: awork, vomat
     630             : 
     631        3904 :       CALL timeset(routineN, handle)
     632             : 
     633        3904 :       nspins = SIZE(residual_vects, 1)
     634        3904 :       nrvs = SIZE(residual_vects, 2)
     635             : 
     636        3904 :       IF (nrvs > 0) THEN
     637        3904 :          CALL dbcsr_get_info(matrix_s, nfullrows_total=nao)
     638       28368 :          ALLOCATE (awork(nspins), vomat(nspins))
     639        8328 :          DO ispin = 1, nspins
     640        4424 :             nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
     641             :             !
     642             :             CALL cp_fm_get_info(matrix=ritz_vects(ispin, 1), matrix_struct=ao_mo_struct, &
     643        4424 :                                 ncol_global=nactive(ispin))
     644        4424 :             CALL cp_fm_create(awork(ispin), ao_mo_struct)
     645             :             !
     646             :             CALL cp_fm_struct_create(virt_mo_struct, nrow_global=nmo_virt(ispin), &
     647        4424 :                                      ncol_global=nactive(ispin), template_fmstruct=ao_mo_struct)
     648        4424 :             CALL cp_fm_create(vomat(ispin), virt_mo_struct)
     649        8328 :             CALL cp_fm_struct_release(virt_mo_struct)
     650             :          END DO
     651             : 
     652             :          ! *** actually compute residual vectors ***
     653       13302 :          DO irv = 1, nrvs
     654        9398 :             lambda = evals(irv)
     655             : 
     656       24226 :             DO ispin = 1, nspins
     657             :                CALL cp_fm_get_info(vomat(ispin), nrow_local=nrows_local, &
     658             :                                    ncol_local=ncols_local, row_indices=row_indices_local, &
     659       10924 :                                    col_indices=col_indices_local, local_data=weights_ldata)
     660             : 
     661             :                ! awork := Ab(ispin, irv) - evals(irv) b(ispin, irv), where 'b' is a Ritz vector
     662             :                CALL cp_dbcsr_sm_fm_multiply(matrix_s, ritz_vects(ispin, irv), awork(ispin), &
     663       10924 :                                             ncol=nactive(ispin), alpha=-lambda, beta=0.0_dp)
     664       10924 :                CALL cp_fm_scale_and_add(1.0_dp, awork(ispin), 1.0_dp, Aop_ritz(ispin, irv))
     665             :                !
     666             :                CALL parallel_gemm('T', 'N', nmo_virt(ispin), nactive(ispin), nao, 1.0_dp, gs_mos(ispin)%mos_virt, &
     667       10924 :                                   awork(ispin), 0.0_dp, vomat(ispin))
     668             : 
     669      100700 :                DO icol_local = 1, ncols_local
     670       89776 :                   e_occ_plus_lambda = gs_mos(ispin)%evals_occ(col_indices_local(icol_local)) + lambda
     671             : 
     672     3374096 :                   DO irow_local = 1, nrows_local
     673     3273396 :                      eref = gs_mos(ispin)%evals_virt(row_indices_local(irow_local)) - e_occ_plus_lambda
     674             : 
     675             :                      ! eref = e_virt - e_occ - lambda = e_virt - e_occ - (eref_scale*lambda + (1-eref_scale)*lambda);
     676             :                      ! eref_new = e_virt - e_occ - eref_scale*lambda = eref + (1 - eref_scale)*lambda
     677     3273396 :                      IF (ABS(eref) < threshold) &
     678          74 :                         eref = eref + (1.0_dp - eref_scale)*lambda
     679             : 
     680     3363172 :                      weights_ldata(irow_local, icol_local) = weights_ldata(irow_local, icol_local)/eref
     681             :                   END DO
     682             :                END DO
     683             : 
     684             :                CALL parallel_gemm('N', 'N', nao, nactive(ispin), nmo_virt(ispin), 1.0_dp, gs_mos(ispin)%mos_virt, &
     685       31246 :                                   vomat(ispin), 0.0_dp, residual_vects(ispin, irv))
     686             :             END DO
     687             :          END DO
     688             :          !
     689        3904 :          CALL cp_fm_release(awork)
     690        7808 :          CALL cp_fm_release(vomat)
     691             :       END IF
     692             : 
     693        3904 :       CALL timestop(handle)
     694             : 
     695        7808 :    END SUBROUTINE tddfpt_compute_residual_vects
     696             : 
     697             : ! **************************************************************************************************
     698             : !> \brief Perform Davidson iterations.
     699             : !> \param evects                TDDFPT trial vectors (modified on exit)
     700             : !> \param evals                 TDDFPT eigenvalues (modified on exit)
     701             : !> \param S_evects              cached matrix product S * evects (modified on exit)
     702             : !> \param gs_mos                molecular orbitals optimised for the ground state
     703             : !> \param tddfpt_control        TDDFPT control parameters
     704             : !> \param matrix_ks             Kohn-Sham matrix
     705             : !> \param qs_env                Quickstep environment
     706             : !> \param kernel_env            kernel environment
     707             : !> \param sub_env               parallel (sub)group environment
     708             : !> \param logger                CP2K logger
     709             : !> \param iter_unit             I/O unit to write basic iteration information
     710             : !> \param energy_unit           I/O unit to write detailed energy information
     711             : !> \param tddfpt_print_section  TDDFPT print input section (need to write TDDFPT restart files)
     712             : !> \param work_matrices         collection of work matrices (modified on exit)
     713             : !> \return energy convergence achieved (in Hartree)
     714             : !> \par History
     715             : !>    * 03.2017 code related to Davidson eigensolver has been moved here from the main subroutine
     716             : !>              tddfpt() [Sergey Chulkov]
     717             : !> \note Based on the subroutines apply_op() and iterative_solver() originally created by
     718             : !>       Thomas Chassaing in 2002.
     719             : ! **************************************************************************************************
     720        2122 :    FUNCTION tddfpt_davidson_solver(evects, evals, S_evects, gs_mos, tddfpt_control, &
     721             :                                    matrix_ks, qs_env, kernel_env, &
     722             :                                    sub_env, logger, iter_unit, energy_unit, &
     723             :                                    tddfpt_print_section, work_matrices) RESULT(conv)
     724             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout)   :: evects
     725             :       REAL(kind=dp), DIMENSION(:), INTENT(inout)         :: evals
     726             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout)   :: S_evects
     727             :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     728             :          INTENT(in)                                      :: gs_mos
     729             :       TYPE(tddfpt2_control_type), POINTER                :: tddfpt_control
     730             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
     731             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     732             :       TYPE(kernel_env_type), INTENT(in)                  :: kernel_env
     733             :       TYPE(tddfpt_subgroup_env_type), INTENT(in)         :: sub_env
     734             :       TYPE(cp_logger_type), POINTER                      :: logger
     735             :       INTEGER, INTENT(in)                                :: iter_unit, energy_unit
     736             :       TYPE(section_vals_type), POINTER                   :: tddfpt_print_section
     737             :       TYPE(tddfpt_work_matrices), INTENT(inout)          :: work_matrices
     738             :       REAL(kind=dp)                                      :: conv
     739             : 
     740             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_davidson_solver'
     741             : 
     742             :       INTEGER                                            :: handle, ispin, istate, iter, &
     743             :                                                             max_krylov_vects, nspins, nstates, &
     744             :                                                             nstates_conv, nvects_exist, nvects_new
     745             :       INTEGER(kind=int_8)                                :: nstates_total
     746             :       LOGICAL                                            :: is_nonortho
     747             :       REAL(kind=dp)                                      :: t1, t2
     748        2122 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: evals_last
     749        2122 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: Atilde
     750        2122 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: Aop_krylov, Aop_ritz, krylov_vects, &
     751        2122 :                                                             S_krylov
     752        2122 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     753             : 
     754        2122 :       CALL timeset(routineN, handle)
     755             : 
     756        2122 :       nspins = SIZE(gs_mos)
     757        2122 :       nstates = tddfpt_control%nstates
     758        2122 :       nstates_total = tddfpt_total_number_of_states(gs_mos)
     759             : 
     760             :       IF (debug_this_module) THEN
     761             :          CPASSERT(SIZE(evects, 1) == nspins)
     762             :          CPASSERT(SIZE(evects, 2) == nstates)
     763             :          CPASSERT(SIZE(evals) == nstates)
     764             :       END IF
     765             : 
     766        2122 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     767             : 
     768             :       ! adjust the number of Krylov vectors
     769        2122 :       max_krylov_vects = tddfpt_control%nkvs
     770        2122 :       IF (max_krylov_vects < nstates) max_krylov_vects = nstates
     771        2122 :       IF (INT(max_krylov_vects, kind=int_8) > nstates_total) max_krylov_vects = INT(nstates_total)
     772             : 
     773       20722 :       ALLOCATE (Aop_ritz(nspins, nstates))
     774        7864 :       DO istate = 1, nstates
     775       14356 :          DO ispin = 1, nspins
     776       12234 :             CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_ritz(ispin, istate))
     777             :          END DO
     778             :       END DO
     779             : 
     780        6366 :       ALLOCATE (evals_last(max_krylov_vects))
     781             :       ALLOCATE (Aop_krylov(nspins, max_krylov_vects), krylov_vects(nspins, max_krylov_vects), &
     782     1620008 :                 S_krylov(nspins, max_krylov_vects))
     783             : 
     784        7864 :       DO istate = 1, nstates
     785       14356 :          DO ispin = 1, nspins
     786        6492 :             CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, krylov_vects(ispin, istate))
     787        6492 :             CALL cp_fm_to_fm(evects(ispin, istate), krylov_vects(ispin, istate))
     788             : 
     789        6492 :             CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, S_krylov(ispin, istate))
     790        6492 :             CALL cp_fm_to_fm(S_evects(ispin, istate), S_krylov(ispin, istate))
     791             : 
     792       12234 :             CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_krylov(ispin, istate))
     793             :          END DO
     794             :       END DO
     795             : 
     796        2122 :       nvects_exist = 0
     797        2122 :       nvects_new = nstates
     798             : 
     799        2122 :       t1 = m_walltime()
     800             : 
     801        2122 :       ALLOCATE (Atilde(1, 1))
     802             : 
     803        6020 :       DO
     804             :          ! davidson iteration
     805        6020 :          CALL cp_iterate(logger%iter_info, iter_nr_out=iter)
     806             : 
     807             :          CALL tddfpt_compute_Aop_evects(Aop_evects=Aop_krylov(:, nvects_exist + 1:nvects_exist + nvects_new), &
     808             :                                         evects=krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
     809             :                                         S_evects=S_krylov(:, nvects_exist + 1:nvects_exist + nvects_new), &
     810             :                                         gs_mos=gs_mos, tddfpt_control=tddfpt_control, &
     811             :                                         matrix_ks=matrix_ks, &
     812             :                                         qs_env=qs_env, kernel_env=kernel_env, &
     813             :                                         sub_env=sub_env, &
     814        6020 :                                         work_matrices=work_matrices)
     815             : 
     816             :          CALL tddfpt_compute_ritz_vects(ritz_vects=evects, Aop_ritz=Aop_ritz, &
     817             :                                         evals=evals_last(1:nvects_exist + nvects_new), &
     818             :                                         krylov_vects=krylov_vects(:, 1:nvects_exist + nvects_new), &
     819             :                                         Aop_krylov=Aop_krylov(:, 1:nvects_exist + nvects_new), &
     820        6020 :                                         Atilde=Atilde, nkvo=nvects_exist, nkvn=nvects_new)
     821             : 
     822             :          CALL tddfpt_write_restart(evects=evects, evals=evals_last(1:nstates), gs_mos=gs_mos, &
     823        6020 :                                    logger=logger, tddfpt_print_section=tddfpt_print_section)
     824             : 
     825       27858 :          conv = MAXVAL(ABS(evals_last(1:nstates) - evals(1:nstates)))
     826             : 
     827        6020 :          nvects_exist = nvects_exist + nvects_new
     828        6020 :          IF (nvects_exist + nvects_new > max_krylov_vects) &
     829         402 :             nvects_new = max_krylov_vects - nvects_exist
     830        6020 :          IF (iter >= tddfpt_control%niters) nvects_new = 0
     831             : 
     832        6020 :          IF (conv > tddfpt_control%conv .AND. nvects_new > 0) THEN
     833             :             ! compute residual vectors for the next iteration
     834       13302 :             DO istate = 1, nvects_new
     835       24226 :                DO ispin = 1, nspins
     836             :                   CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
     837       10924 :                                          krylov_vects(ispin, nvects_exist + istate))
     838             :                   CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
     839       10924 :                                          S_krylov(ispin, nvects_exist + istate))
     840             :                   CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
     841       20322 :                                          Aop_krylov(ispin, nvects_exist + istate))
     842             :                END DO
     843             :             END DO
     844             : 
     845             :             CALL tddfpt_compute_residual_vects(residual_vects=krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
     846             :                                                evals=evals_last(1:nvects_new), &
     847             :                                                ritz_vects=evects(:, 1:nvects_new), Aop_ritz=Aop_ritz(:, 1:nvects_new), &
     848        3904 :                                                gs_mos=gs_mos, matrix_s=matrix_s(1)%matrix)
     849             : 
     850             :             CALL tddfpt_orthogonalize_psi1_psi0(krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
     851        3904 :                                                 work_matrices%S_C0_C0T)
     852             : 
     853             :             CALL tddfpt_orthonormalize_psi1_psi1(krylov_vects(:, 1:nvects_exist + nvects_new), nvects_new, &
     854        3904 :                                                  S_krylov(:, 1:nvects_exist + nvects_new), matrix_s(1)%matrix)
     855             : 
     856             :             is_nonortho = tddfpt_is_nonorthogonal_psi1_psi0(krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
     857        3904 :                                                             work_matrices%S_C0, tddfpt_control%orthogonal_eps)
     858             :          ELSE
     859             :             ! convergence or the maximum number of Krylov vectors have been achieved
     860        2116 :             nvects_new = 0
     861        2116 :             is_nonortho = .FALSE.
     862             :          END IF
     863             : 
     864        6020 :          t2 = m_walltime()
     865        6020 :          IF (energy_unit > 0) THEN
     866         375 :             WRITE (energy_unit, '(/,4X,A,T14,A,T36,A)') "State", "Exc. energy (eV)", "Convergence (eV)"
     867         867 :             DO istate = 1, nstates
     868         492 :                WRITE (energy_unit, '(1X,I8,T12,F14.7,T38,ES11.4)') istate, &
     869        1359 :                   evals_last(istate)*evolt, (evals_last(istate) - evals(istate))*evolt
     870             :             END DO
     871         375 :             WRITE (energy_unit, *)
     872         375 :             CALL m_flush(energy_unit)
     873             :          END IF
     874             : 
     875        6020 :          IF (iter_unit > 0) THEN
     876        3010 :             nstates_conv = 0
     877       10919 :             DO istate = 1, nstates
     878        7909 :                IF (ABS(evals_last(istate) - evals(istate)) <= tddfpt_control%conv) &
     879        6523 :                   nstates_conv = nstates_conv + 1
     880             :             END DO
     881             : 
     882        3010 :             WRITE (iter_unit, '(T7,I8,T24,F7.1,T40,ES11.4,T66,I8)') iter, t2 - t1, conv, nstates_conv
     883        3010 :             CALL m_flush(iter_unit)
     884             :          END IF
     885             : 
     886       21838 :          t1 = t2
     887       21838 :          evals(1:nstates) = evals_last(1:nstates)
     888             : 
     889             :          ! nvects_new == 0 if iter >= tddfpt_control%niters
     890        6020 :          IF (nvects_new == 0 .OR. is_nonortho) THEN
     891             :             ! restart Davidson iterations
     892        2122 :             CALL tddfpt_orthogonalize_psi1_psi0(evects, work_matrices%S_C0_C0T)
     893        2122 :             CALL tddfpt_orthonormalize_psi1_psi1(evects, nstates, S_evects, matrix_s(1)%matrix)
     894             : 
     895             :             EXIT
     896             :          END IF
     897             :       END DO
     898             : 
     899        2122 :       DEALLOCATE (Atilde)
     900             : 
     901       17262 :       DO istate = nvects_exist + nvects_new, 1, -1
     902       34678 :          DO ispin = nspins, 1, -1
     903       17416 :             CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_krylov(ispin, istate))
     904       17416 :             CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, S_krylov(ispin, istate))
     905       32556 :             CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, krylov_vects(ispin, istate))
     906             :          END DO
     907             :       END DO
     908        2122 :       DEALLOCATE (Aop_krylov, krylov_vects, S_krylov)
     909        2122 :       DEALLOCATE (evals_last)
     910             : 
     911        7864 :       DO istate = nstates, 1, -1
     912       14356 :          DO ispin = nspins, 1, -1
     913       12234 :             CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_ritz(ispin, istate))
     914             :          END DO
     915             :       END DO
     916        2122 :       DEALLOCATE (Aop_ritz)
     917             : 
     918        2122 :       CALL timestop(handle)
     919             : 
     920        2122 :    END FUNCTION tddfpt_davidson_solver
     921             : 
     922             : END MODULE qs_tddfpt2_eigensolver

Generated by: LCOV version 1.15