LCOV - code coverage report
Current view: top level - src - qs_tddfpt2_eigensolver.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 95.6 % 321 307
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 7 7

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

Generated by: LCOV version 2.0-1