LCOV - code coverage report
Current view: top level - src - qs_tddfpt_eigensolver.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 205 218 94.0 %
Date: 2024-12-21 06:28:57 Functions: 4 4 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             : ! **************************************************************************************************
       9             : MODULE qs_tddfpt_eigensolver
      10             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      11             :    USE cp_control_types,                ONLY: dft_control_type,&
      12             :                                               tddfpt_control_type
      13             :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type,&
      14             :                                               dbcsr_set
      15             :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_plus_fm_fm_t,&
      16             :                                               cp_dbcsr_sm_fm_multiply
      17             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add,&
      18             :                                               cp_fm_symm,&
      19             :                                               cp_fm_trace
      20             :    USE cp_fm_diag,                      ONLY: cp_fm_syevd
      21             :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      22             :                                               fm_pools_create_fm_vect,&
      23             :                                               fm_pools_give_back_fm_vect
      24             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      25             :                                               cp_fm_struct_p_type,&
      26             :                                               cp_fm_struct_release,&
      27             :                                               cp_fm_struct_type
      28             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      29             :                                               cp_fm_get_element,&
      30             :                                               cp_fm_release,&
      31             :                                               cp_fm_set_all,&
      32             :                                               cp_fm_set_element,&
      33             :                                               cp_fm_to_fm,&
      34             :                                               cp_fm_type
      35             :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit,&
      36             :                                               cp_to_string
      37             :    USE input_constants,                 ONLY: tddfpt_davidson,&
      38             :                                               tddfpt_lanczos
      39             :    USE kinds,                           ONLY: default_string_length,&
      40             :                                               dp
      41             :    USE message_passing,                 ONLY: mp_para_env_type
      42             :    USE physcon,                         ONLY: evolt
      43             :    USE qs_environment_types,            ONLY: get_qs_env,&
      44             :                                               qs_environment_type
      45             :    USE qs_matrix_pools,                 ONLY: mpools_get
      46             :    USE qs_p_env_methods,                ONLY: p_op_l1,&
      47             :                                               p_op_l2,&
      48             :                                               p_postortho,&
      49             :                                               p_preortho
      50             :    USE qs_p_env_types,                  ONLY: qs_p_env_type
      51             :    USE qs_tddfpt_types,                 ONLY: tddfpt_env_type
      52             :    USE qs_tddfpt_utils,                 ONLY: co_initial_guess,&
      53             :                                               normalize,&
      54             :                                               reorthogonalize
      55             : #include "./base/base_uses.f90"
      56             : 
      57             :    IMPLICIT NONE
      58             : 
      59             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt_eigensolver'
      60             : 
      61             :    PRIVATE
      62             : 
      63             :    PUBLIC :: eigensolver
      64             : 
      65             : CONTAINS
      66             : 
      67             : ! **************************************************************************************************
      68             : !> \brief ...
      69             : !> \param p_env ...
      70             : !> \param qs_env ...
      71             : !> \param t_env ...
      72             : ! **************************************************************************************************
      73          12 :    SUBROUTINE eigensolver(p_env, qs_env, t_env)
      74             : 
      75             :       TYPE(qs_p_env_type)                                :: p_env
      76             :       TYPE(qs_environment_type), POINTER                 :: qs_env
      77             :       TYPE(tddfpt_env_type), INTENT(INOUT)               :: t_env
      78             : 
      79             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'eigensolver'
      80             : 
      81             :       INTEGER                                            :: handle, n_ev, nspins, output_unit, &
      82             :                                                             restarts
      83             :       LOGICAL                                            :: do_kernel_save
      84             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ievals
      85             :       TYPE(dft_control_type), POINTER                    :: dft_control
      86             : 
      87          12 :       CALL timeset(routineN, handle)
      88             : 
      89          12 :       NULLIFY (dft_control)
      90             : 
      91          12 :       output_unit = cp_logger_get_default_io_unit()
      92             : 
      93          12 :       CALL get_qs_env(qs_env, dft_control=dft_control)
      94          12 :       n_ev = dft_control%tddfpt_control%n_ev
      95          12 :       nspins = dft_control%nspins
      96             : 
      97          36 :       ALLOCATE (ievals(n_ev))
      98             : 
      99             :       !---------------!
     100             :       ! initial guess !
     101             :       !---------------!
     102          12 :       do_kernel_save = dft_control%tddfpt_control%do_kernel
     103          12 :       dft_control%tddfpt_control%do_kernel = .FALSE.
     104          12 :       IF (output_unit > 0) THEN
     105           6 :          WRITE (output_unit, *) " Generating initial guess"
     106           6 :          WRITE (output_unit, *)
     107             :       END IF
     108          12 :       IF (ASSOCIATED(dft_control%tddfpt_control%lumos)) THEN
     109          12 :          CALL co_initial_guess(t_env%evecs, ievals, n_ev, qs_env)
     110             :       ELSE
     111           0 :          IF (output_unit > 0) WRITE (output_unit, *) "LUMOS are needed in TDDFPT!"
     112           0 :          CPABORT("")
     113             :       END IF
     114          12 :       DO restarts = 1, dft_control%tddfpt_control%n_restarts
     115          12 :          IF (iterative_solver(ievals, t_env, p_env, qs_env, ievals)) EXIT
     116          12 :          IF (output_unit > 0) THEN
     117           0 :             WRITE (output_unit, *) " Restarting"
     118           0 :             WRITE (output_unit, *)
     119             :          END IF
     120             :       END DO
     121          12 :       dft_control%tddfpt_control%do_kernel = do_kernel_save
     122             : 
     123             :       !-----------------!
     124             :       ! call the solver !
     125             :       !-----------------!
     126          12 :       IF (output_unit > 0) THEN
     127           6 :          WRITE (output_unit, *)
     128           6 :          WRITE (output_unit, *) " Doing TDDFPT calculation"
     129           6 :          WRITE (output_unit, *)
     130             :       END IF
     131          36 :       DO restarts = 1, dft_control%tddfpt_control%n_restarts
     132          24 :          IF (iterative_solver(ievals, t_env, p_env, qs_env, t_env%evals)) EXIT
     133          36 :          IF (output_unit > 0) THEN
     134          12 :             WRITE (output_unit, *) " Restarting"
     135          12 :             WRITE (output_unit, *)
     136             :          END IF
     137             :       END DO
     138             : 
     139             :       !---------!
     140             :       ! cleanup !
     141             :       !---------!
     142          12 :       DEALLOCATE (ievals)
     143             : 
     144          12 :       CALL timestop(handle)
     145             : 
     146          12 :    END SUBROUTINE eigensolver
     147             : 
     148             :    ! in_evals  : approximations to the eigenvalues for the preconditioner
     149             :    ! t_env     : TD-DFT environment values
     150             :    ! p_env     : perturbation environment values
     151             :    ! qs_env    : general Quickstep environment values
     152             :    ! out_evals : the resulting eigenvalues
     153             :    ! error     : used for error handling
     154             :    !
     155             :    ! res       : the function will return wheter the eigenvalues are converged or not
     156             : 
     157             : ! **************************************************************************************************
     158             : !> \brief ...
     159             : !> \param in_evals ...
     160             : !> \param t_env ...
     161             : !> \param p_env ...
     162             : !> \param qs_env ...
     163             : !> \param out_evals ...
     164             : !> \return ...
     165             : ! **************************************************************************************************
     166          36 :    FUNCTION iterative_solver(in_evals, &
     167             :                              t_env, p_env, qs_env, &
     168          36 :                              out_evals) RESULT(res)
     169             : 
     170             :       REAL(KIND=dp), DIMENSION(:)                        :: in_evals
     171             :       TYPE(tddfpt_env_type), INTENT(INOUT)               :: t_env
     172             :       TYPE(qs_p_env_type)                                :: p_env
     173             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     174             :       REAL(kind=dp), DIMENSION(:), OPTIONAL              :: out_evals
     175             :       LOGICAL                                            :: res
     176             : 
     177             :       CHARACTER(len=*), PARAMETER :: routineN = 'iterative_solver', &
     178             :          routineP = moduleN//':'//routineN
     179             : 
     180             :       CHARACTER                                          :: mode
     181             :       INTEGER                                            :: col, handle, i, iev, iter, j, k, &
     182             :                                                             max_krylovspace_dim, max_kv, n_ev, &
     183             :                                                             n_kv, nspins, output_unit, row, spin
     184          36 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: must_improve
     185             :       REAL(dp)                                           :: Atilde_ij, convergence, tmp, tmp2
     186          36 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: evals_difference, evals_tmp
     187          36 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: evals
     188             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     189          36 :       TYPE(cp_fm_pool_p_type), DIMENSION(:), POINTER     :: ao_mo_fm_pools
     190             :       TYPE(cp_fm_struct_p_type), ALLOCATABLE, &
     191          36 :          DIMENSION(:)                                    :: kv_fm_struct
     192             :       TYPE(cp_fm_struct_type), POINTER                   :: tilde_fm_struct
     193             :       TYPE(cp_fm_type)                                   :: Atilde, Us
     194          36 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: R, X
     195          36 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: Ab, b, Sb
     196          36 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     197             :       TYPE(dft_control_type), POINTER                    :: dft_control
     198             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     199             :       TYPE(tddfpt_control_type), POINTER                 :: tddfpt_control
     200             : 
     201          36 :       res = .FALSE.
     202             : 
     203          36 :       CALL timeset(routineN, handle)
     204             : 
     205          36 :       NULLIFY (ao_mo_fm_pools, tddfpt_control, &
     206          36 :                tilde_fm_struct, matrix_s, dft_control, &
     207          36 :                para_env, blacs_env)
     208             : 
     209             :       CALL get_qs_env(qs_env, &
     210             :                       matrix_s=matrix_s, &
     211             :                       dft_control=dft_control, &
     212             :                       para_env=para_env, &
     213          36 :                       blacs_env=blacs_env)
     214             : 
     215          36 :       tddfpt_control => dft_control%tddfpt_control
     216          36 :       output_unit = cp_logger_get_default_io_unit()
     217          36 :       n_ev = tddfpt_control%n_ev
     218          36 :       nspins = dft_control%nspins
     219             : 
     220          36 :       IF (dft_control%tddfpt_control%diag_method == tddfpt_lanczos) THEN
     221             :          mode = 'L'
     222          36 :       ELSE IF (dft_control%tddfpt_control%diag_method == tddfpt_davidson) THEN
     223          36 :          mode = 'D'
     224             :       END IF
     225             : 
     226             :       !-----------------------------------------!
     227             :       ! determine the size of the problem       !
     228             :       ! and how many krylov space vetors to use !
     229             :       !-----------------------------------------!
     230          84 :       max_krylovspace_dim = SUM(p_env%n_ao(1:nspins)*p_env%n_mo(1:nspins))
     231          36 :       max_kv = tddfpt_control%max_kv
     232          36 :       IF (max_krylovspace_dim <= max_kv) THEN
     233           6 :          max_kv = max_krylovspace_dim
     234           6 :          IF (output_unit > 0) THEN
     235           3 :             WRITE (output_unit, *) "  Setting the maximum number of krylov vectors to ", max_kv, "!"
     236             :          END IF
     237             :       END IF
     238             : 
     239             :       !----------------------!
     240             :       ! allocate the vectors !
     241             :       !----------------------!
     242          36 :       CALL mpools_get(qs_env%mpools, ao_mo_fm_pools=ao_mo_fm_pools)
     243          36 :       CALL fm_pools_create_fm_vect(ao_mo_fm_pools, X, name=routineP//":X")
     244          36 :       CALL fm_pools_create_fm_vect(ao_mo_fm_pools, R, name=routineP//":R")
     245             : 
     246         108 :       ALLOCATE (evals_difference(n_ev))
     247             : 
     248         108 :       ALLOCATE (must_improve(n_ev))
     249             : 
     250         144 :       ALLOCATE (evals(max_kv, 0:max_kv))
     251         108 :       ALLOCATE (evals_tmp(max_kv))
     252             : 
     253           0 :       ALLOCATE (b(max_kv, nspins), Ab(max_kv, nspins), &
     254        3024 :                 Sb(max_kv, nspins))
     255             : 
     256         156 :       ALLOCATE (kv_fm_struct(nspins))
     257             : 
     258          84 :       DO spin = 1, nspins
     259             :          CALL cp_fm_struct_create(kv_fm_struct(spin)%struct, para_env, blacs_env, &
     260          84 :                                   p_env%n_ao(spin), p_env%n_mo(spin))
     261             :       END DO
     262             : 
     263          36 :       IF (output_unit > 0) THEN
     264             :          WRITE (output_unit, '(2X,A,T69,A)') &
     265          18 :             "nvec", "Convergence"
     266             :          WRITE (output_unit, '(2X,A)') &
     267          18 :             "-----------------------------------------------------------------------------"
     268             :       END IF
     269             : 
     270          36 :       iter = 1
     271          36 :       k = 0
     272          36 :       n_kv = n_ev
     273         496 :       iteration: DO
     274             : 
     275         248 :          CALL allocate_krylov_vectors(b, "b-", k + 1, n_kv, nspins, kv_fm_struct)
     276         248 :          CALL allocate_krylov_vectors(Ab, "Ab-", k + 1, n_kv, nspins, kv_fm_struct)
     277         248 :          CALL allocate_krylov_vectors(Sb, "Sb-", k + 1, n_kv, nspins, kv_fm_struct)
     278             : 
     279         792 :          DO i = 1, n_kv
     280         544 :             k = k + 1
     281             : 
     282         544 :             IF (k <= SIZE(t_env%evecs, 1)) THEN ! the first iteration
     283             : 
     284             :                ! take the initial guess
     285         228 :                DO spin = 1, nspins
     286         228 :                   CALL cp_fm_to_fm(t_env%evecs(k, spin), b(k, spin))
     287             :                END DO
     288             : 
     289             :             ELSE
     290             : 
     291             :                ! create a new vector
     292         448 :                IF (mode == 'L') THEN
     293             : 
     294           0 :                   DO spin = 1, nspins
     295           0 :                      IF (tddfpt_control%invert_S) THEN
     296             :                         CALL cp_fm_symm('L', 'U', p_env%n_ao(spin), p_env%n_mo(spin), &
     297             :                                         1.0_dp, t_env%invS(spin), Ab(k - 1, spin), &
     298           0 :                                         0.0_dp, b(k, spin))
     299             :                      ELSE
     300           0 :                         CALL cp_fm_to_fm(Ab(k - 1, spin), b(k, spin))
     301             :                      END IF
     302             :                   END DO
     303             : 
     304         448 :                ELSE IF (mode == 'D') THEN
     305             : 
     306         448 :                   iev = must_improve(i)
     307             :                   ! create the new davidson vector
     308         956 :                   DO spin = 1, nspins
     309             : 
     310         508 :                      CALL cp_fm_set_all(R(spin), 0.0_dp)
     311        9194 :                      DO j = 1, k - i
     312        8686 :                         CALL cp_fm_to_fm(Ab(j, spin), X(spin))
     313             :                         CALL cp_fm_scale_and_add(1.0_dp, X(spin), &
     314        8686 :                                                  -evals(iev, iter - 1), Sb(j, spin))
     315        8686 :                         CALL cp_fm_get_element(Us, j, iev, tmp)
     316             :                         CALL cp_fm_scale_and_add(1.0_dp, R(spin), &
     317        9194 :                                                  tmp, X(spin))
     318             :                      END DO
     319             : 
     320         508 :                      IF (tddfpt_control%invert_S) THEN
     321             :                         CALL cp_fm_symm('L', 'U', p_env%n_ao(spin), p_env%n_mo(spin), &
     322             :                                         1.0_dp, t_env%invS(spin), R(spin), &
     323         508 :                                         0.0_dp, X(spin))
     324             :                      ELSE
     325           0 :                         CALL cp_fm_to_fm(R(spin), X(spin))
     326             :                      END IF
     327             : 
     328             :                      !----------------!
     329             :                      ! preconditioner !
     330             :                      !----------------!
     331         956 :                      IF (dft_control%tddfpt_control%precond) THEN
     332         900 :                         DO col = 1, p_env%n_mo(spin)
     333         720 :                            IF (col <= n_ev) THEN
     334         540 :                               tmp2 = ABS(evals(iev, iter - 1) - in_evals(col))
     335             :                            ELSE
     336         180 :                               tmp2 = ABS(evals(iev, iter - 1) - (in_evals(n_ev) + 10.0_dp))
     337             :                            END IF
     338             :                            ! protect against division by 0 by a introducing a cutoff.
     339         720 :                            tmp2 = MAX(tmp2, 100*EPSILON(1.0_dp))
     340       17460 :                            DO row = 1, p_env%n_ao(spin)
     341       16560 :                               CALL cp_fm_get_element(X(spin), row, col, tmp)
     342       17280 :                               CALL cp_fm_set_element(b(k, spin), row, col, tmp/tmp2)
     343             :                            END DO
     344             :                         END DO
     345             :                      ELSE
     346         328 :                         CALL cp_fm_to_fm(X(spin), b(k, spin))
     347             :                      END IF
     348             : 
     349             :                   END DO
     350             : 
     351             :                ELSE
     352           0 :                   IF (output_unit > 0) WRITE (output_unit, *) "unknown mode"
     353           0 :                   CPABORT("")
     354             :                END IF
     355             : 
     356             :             END IF
     357             : 
     358         544 :             CALL p_preortho(p_env, qs_env, b(k, :))
     359        1632 :             DO j = 1, tddfpt_control%n_reortho
     360        1632 :                CALL reorthogonalize(b(k, :), b, Sb, R, k - 1) ! R is temp
     361             :             END DO
     362         544 :             CALL normalize(b(k, :), R, matrix_s) ! R is temp
     363        1184 :             DO spin = 1, nspins
     364        1184 :                CALL cp_fm_to_fm(b(k, spin), X(spin))
     365             :             END DO
     366             :             CALL apply_op(X, Ab(k, :), p_env, qs_env, &
     367         544 :                           dft_control%tddfpt_control%do_kernel)
     368         544 :             CALL p_postortho(p_env, qs_env, Ab(k, :))
     369        1432 :             DO spin = 1, nspins
     370             :                CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, &
     371             :                                             b(k, spin), &
     372             :                                             Sb(k, spin), &
     373        1184 :                                             p_env%n_mo(spin))
     374             :             END DO
     375             :          END DO
     376             : 
     377             :          !--------------------------------------------!
     378             :          ! deallocate memory for the reduced matrices !
     379             :          !--------------------------------------------!
     380         248 :          CALL cp_fm_release(Atilde)
     381         248 :          CALL cp_fm_release(Us)
     382         248 :          IF (ASSOCIATED(tilde_fm_struct)) CALL cp_fm_struct_release(tilde_fm_struct)
     383             : 
     384             :          !------------------------------------------!
     385             :          ! allocate memory for the reduced matrices !
     386             :          !------------------------------------------!
     387         248 :          CALL cp_fm_struct_create(tilde_fm_struct, para_env, blacs_env, k, k)
     388             :          CALL cp_fm_create(Atilde, &
     389             :                            tilde_fm_struct, &
     390         248 :                            routineP//"Atilde")
     391             :          CALL cp_fm_create(Us, &
     392             :                            tilde_fm_struct, &
     393         248 :                            routineP//"Us")
     394             : 
     395             :          !---------------------------------------!
     396             :          ! calc the matrix Atilde = transp(b)*Ab !
     397             :          !---------------------------------------!
     398        5066 :          DO i = 1, k
     399      168824 :             DO j = 1, k
     400      163758 :                Atilde_ij = 0.0_dp
     401      328704 :                DO spin = 1, nspins
     402      164946 :                   CALL cp_fm_trace(b(i, spin), Ab(j, spin), tmp)
     403      328704 :                   Atilde_ij = Atilde_ij + tmp
     404             :                END DO
     405      168576 :                CALL cp_fm_set_element(Atilde, i, j, Atilde_ij)
     406             :             END DO
     407             :          END DO
     408             : 
     409             :          !--------------------!
     410             :          ! diagonalize Atilde !
     411             :          !--------------------!
     412        9984 :          evals_tmp(:) = evals(:, iter)
     413         248 :          CALL cp_fm_syevd(Atilde, Us, evals_tmp(:))
     414        9984 :          evals(:, iter) = evals_tmp(:)
     415             : 
     416             :          !-------------------!
     417             :          ! check convergence !
     418             :          !-------------------!
     419         808 :          evals_difference = 1.0_dp
     420         248 :          IF (iter /= 1) THEN
     421             : 
     422         676 :             evals_difference(:) = ABS((evals(1:n_ev, iter - 1) - evals(1:n_ev, iter)))
     423             :             ! For debugging
     424         212 :             IF (output_unit > 0) THEN
     425         106 :                WRITE (output_unit, *)
     426         338 :                DO i = 1, n_ev
     427         338 :                   WRITE (output_unit, '(2X,F10.7,T69,ES11.4)') evals(i, iter)*evolt, evals_difference(i)
     428             :                END DO
     429         106 :                WRITE (output_unit, *)
     430             :             END IF
     431             : 
     432         888 :             convergence = MAXVAL(evals_difference)
     433         212 :             IF (output_unit > 0) WRITE (output_unit, '(2X,I4,T69,ES11.4)') k, convergence
     434             : 
     435         212 :             IF (convergence < tddfpt_control%tolerance) THEN
     436             :                res = .TRUE.
     437             :                EXIT iteration
     438             :             END IF
     439             :          END IF
     440             : 
     441         236 :          IF (mode == 'L') THEN
     442           0 :             n_kv = 1
     443             :          ELSE
     444         764 :             must_improve = 0
     445         764 :             DO i = 1, n_ev
     446         764 :                IF (evals_difference(i) > tddfpt_control%tolerance) must_improve(i) = 1
     447             :             END DO
     448             : !! Set must_improve to 1 if all the vectors should
     449             : !! be updated in one iteration.
     450             : !!          must_improve = 1
     451         764 :             n_kv = SUM(must_improve)
     452         236 :             j = 1
     453         764 :             DO i = 1, n_ev
     454         764 :                IF (must_improve(i) == 1) THEN
     455         512 :                   must_improve(j) = i
     456         512 :                   j = j + 1
     457             :                END IF
     458             :             END DO
     459             :          END IF
     460             : 
     461         236 :          IF (k + n_kv > max_kv) EXIT iteration
     462             : 
     463         212 :          iter = iter + 1
     464             : 
     465             :       END DO iteration
     466             : 
     467          36 :       IF (PRESENT(out_evals)) THEN
     468         132 :          out_evals(1:n_ev) = evals(1:n_ev, iter)
     469             :       END IF
     470             : 
     471          84 :       DO spin = 1, nspins
     472         216 :          DO j = 1, n_ev
     473         132 :             CALL cp_fm_set_all(t_env%evecs(j, spin), 0.0_dp)
     474        1748 :             DO i = 1, k
     475        1568 :                CALL cp_fm_get_element(Us, i, j, tmp)
     476             :                CALL cp_fm_scale_and_add(1.0_dp, t_env%evecs(j, spin), &
     477        1700 :                                         tmp, b(i, spin))
     478             :             END DO
     479             :          END DO
     480             :       END DO
     481             : 
     482             :       !----------!
     483             :       ! clean up !
     484             :       !----------!
     485          36 :       CALL cp_fm_release(Atilde)
     486          36 :       CALL cp_fm_release(Us)
     487          36 :       IF (ASSOCIATED(tilde_fm_struct)) CALL cp_fm_struct_release(tilde_fm_struct)
     488          36 :       CALL fm_pools_give_back_fm_vect(ao_mo_fm_pools, X)
     489          36 :       CALL fm_pools_give_back_fm_vect(ao_mo_fm_pools, R)
     490          84 :       DO spin = 1, nspins
     491          84 :          CALL cp_fm_struct_release(kv_fm_struct(spin)%struct)
     492             :       END DO
     493          36 :       CALL cp_fm_release(b)
     494          36 :       CALL cp_fm_release(Ab)
     495          36 :       CALL cp_fm_release(Sb)
     496          36 :       DEALLOCATE (evals, evals_tmp, evals_difference, must_improve, kv_fm_struct)
     497             : 
     498          36 :       CALL timestop(handle)
     499             : 
     500          72 :    END FUNCTION iterative_solver
     501             : 
     502             :    ! X        : the vector on which to apply the op
     503             :    ! R        : the result
     504             :    ! t_env    : td-dft environment (mainly control information)
     505             :    ! p_env    : perturbation environment (variables)
     506             :    !            both of these carry info for the tddfpt calculation
     507             :    ! qs_env   : info about a quickstep ground state calculation
     508             : 
     509             : ! **************************************************************************************************
     510             : !> \brief ...
     511             : !> \param X ...
     512             : !> \param R ...
     513             : !> \param p_env ...
     514             : !> \param qs_env ...
     515             : !> \param do_kernel ...
     516             : ! **************************************************************************************************
     517         544 :    SUBROUTINE apply_op(X, R, p_env, qs_env, do_kernel)
     518             : 
     519             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: X, R
     520             :       TYPE(qs_p_env_type)                                :: p_env
     521             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     522             :       LOGICAL, INTENT(IN)                                :: do_kernel
     523             : 
     524             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_op'
     525             : 
     526             :       INTEGER                                            :: handle, nspins, spin
     527             :       INTEGER, SAVE                                      :: counter = 0
     528             :       TYPE(dft_control_type), POINTER                    :: dft_control
     529             : 
     530         544 :       NULLIFY (dft_control)
     531             : 
     532         544 :       CALL timeset(routineN, handle)
     533             : 
     534         544 :       counter = counter + 1
     535         544 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     536         544 :       nspins = dft_control%nspins
     537             : 
     538             :       !------------!
     539             :       ! R = HX-SXL !
     540             :       !------------!
     541         544 :       CALL p_op_l1(p_env, qs_env, X, R) ! acts on both spins, result in R
     542             : 
     543             :       !-----------------!
     544             :       ! calc P1 and     !
     545             :       ! R = R + K(P1)*C !
     546             :       !-----------------!
     547         544 :       IF (do_kernel) THEN
     548        1028 :          DO spin = 1, nspins
     549         550 :             CALL dbcsr_set(p_env%p1(spin)%matrix, 0.0_dp) ! optimize?
     550             :             CALL cp_dbcsr_plus_fm_fm_t(p_env%p1(spin)%matrix, &
     551             :                                        matrix_v=p_env%psi0d(spin), &
     552             :                                        matrix_g=X(spin), &
     553             :                                        ncol=p_env%n_mo(spin), &
     554        1028 :                                        symmetry_mode=1)
     555             :          END DO
     556        1028 :          DO spin = 1, nspins
     557        1028 :             CALL cp_fm_set_all(X(spin), 0.0_dp)
     558             :          END DO
     559             :          CALL p_op_l2(p_env, qs_env, p_env%p1, X, &
     560         478 :                       alpha=1.0_dp, beta=0.0_dp) ! X = beta*X + alpha*K(P1)*C
     561        1028 :          DO spin = 1, nspins
     562             :             CALL cp_fm_scale_and_add(1.0_dp, R(spin), &
     563        1028 :                                      1.0_dp, X(spin)) ! add X to R
     564             :          END DO
     565             :       END IF
     566             : 
     567         544 :       CALL timestop(handle)
     568             : 
     569         544 :    END SUBROUTINE apply_op
     570             : 
     571             : ! **************************************************************************************************
     572             : !> \brief ...
     573             : !> \param vectors ...
     574             : !> \param vectors_name ...
     575             : !> \param startv ...
     576             : !> \param n_v ...
     577             : !> \param nspins ...
     578             : !> \param fm_struct ...
     579             : ! **************************************************************************************************
     580         744 :    SUBROUTINE allocate_krylov_vectors(vectors, vectors_name, &
     581         744 :                                       startv, n_v, nspins, fm_struct)
     582             : 
     583             :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: vectors
     584             :       CHARACTER(LEN=*), INTENT(IN)                       :: vectors_name
     585             :       INTEGER, INTENT(IN)                                :: startv, n_v, nspins
     586             :       TYPE(cp_fm_struct_p_type), DIMENSION(:), &
     587             :          INTENT(IN)                                      :: fm_struct
     588             : 
     589             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'allocate_krylov_vectors', &
     590             :          routineP = moduleN//':'//routineN
     591             : 
     592             :       CHARACTER(LEN=default_string_length)               :: mat_name
     593             :       INTEGER                                            :: index, spin
     594             : 
     595        1584 :       DO spin = 1, nspins
     596        3504 :          DO index = startv, startv + n_v - 1
     597             :             mat_name = routineP//vectors_name//TRIM(cp_to_string(index)) &
     598        1920 :                        //","//TRIM(cp_to_string(spin))
     599             :             CALL cp_fm_create(vectors(index, spin), &
     600        1920 :                               fm_struct(spin)%struct, mat_name)
     601        1920 :             IF (.NOT. ASSOCIATED(vectors(index, spin)%matrix_struct)) &
     602         840 :                CPABORT("Could not allocate "//TRIM(mat_name)//".")
     603             :          END DO
     604             :       END DO
     605             : 
     606         744 :    END SUBROUTINE allocate_krylov_vectors
     607             : 
     608             : END MODULE qs_tddfpt_eigensolver

Generated by: LCOV version 1.15