LCOV - code coverage report
Current view: top level - src - qs_scf_lanczos.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 58.1 % 442 257
Test Date: 2026-10-15 00:55:44 Functions: 66.7 % 3 2

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief module that contains the algorithms to perform an iterative
      10              : !>         diagonalization by the block-Lanczos approach
      11              : !> \par History
      12              : !>      05.2009 created [MI]
      13              : !> \author fawzi
      14              : ! **************************************************************************************************
      15              : MODULE qs_scf_lanczos
      16              : 
      17              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      18              :                                               cp_fm_qr_factorization,&
      19              :                                               cp_fm_scale_and_add,&
      20              :                                               cp_fm_transpose,&
      21              :                                               cp_fm_triangular_multiply
      22              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      23              :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      24              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      25              :                                               cp_fm_struct_release,&
      26              :                                               cp_fm_struct_type
      27              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      28              :                                               cp_fm_get_submatrix,&
      29              :                                               cp_fm_release,&
      30              :                                               cp_fm_set_all,&
      31              :                                               cp_fm_set_submatrix,&
      32              :                                               cp_fm_to_fm,&
      33              :                                               cp_fm_type,&
      34              :                                               cp_fm_vectorsnorm
      35              :    USE cp_log_handling,                 ONLY: cp_to_string
      36              :    USE kinds,                           ONLY: dp
      37              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      38              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      39              :                                               mo_set_type
      40              :    USE qs_scf_types,                    ONLY: krylov_space_type
      41              :    USE scf_control_types,               ONLY: scf_control_type
      42              : #include "./base/base_uses.f90"
      43              : 
      44              :    IMPLICIT NONE
      45              :    PRIVATE
      46              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_lanczos'
      47              : 
      48              :    PUBLIC :: krylov_space_allocate, lanczos_refinement, lanczos_refinement_2v
      49              : 
      50              : CONTAINS
      51              : 
      52              : ! **************************************************************************************************
      53              : 
      54              : ! **************************************************************************************************
      55              : !> \brief  allocates matrices and vectors used in the construction of
      56              : !>        the krylov space and for the lanczos refinement
      57              : !> \param krylov_space ...
      58              : !> \param scf_control ...
      59              : !> \param mos ...
      60              : !> \param
      61              : !> \par History
      62              : !>      05.2009 created [MI]
      63              : ! **************************************************************************************************
      64              : 
      65           10 :    SUBROUTINE krylov_space_allocate(krylov_space, scf_control, mos)
      66              : 
      67              :       TYPE(krylov_space_type), INTENT(INOUT)             :: krylov_space
      68              :       TYPE(scf_control_type), POINTER                    :: scf_control
      69              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mos
      70              : 
      71              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'krylov_space_allocate'
      72              : 
      73              :       INTEGER                                            :: handle, ik, ispin, max_nmo, nao, nblock, &
      74              :                                                             ndim, nk, nmo, nspin
      75              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
      76              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
      77              : 
      78           10 :       CALL timeset(routineN, handle)
      79              : 
      80           10 :       IF (.NOT. ASSOCIATED(krylov_space%mo_conv)) THEN
      81            6 :          NULLIFY (fm_struct_tmp, mo_coeff)
      82              : 
      83            6 :          krylov_space%nkrylov = scf_control%diagonalization%nkrylov
      84            6 :          krylov_space%nblock = scf_control%diagonalization%nblock_krylov
      85              : 
      86            6 :          nk = krylov_space%nkrylov
      87            6 :          nblock = krylov_space%nblock
      88            6 :          nspin = SIZE(mos, 1)
      89              : 
      90           24 :          ALLOCATE (krylov_space%mo_conv(nspin))
      91           18 :          ALLOCATE (krylov_space%mo_refine(nspin))
      92           18 :          ALLOCATE (krylov_space%chc_mat(nspin))
      93           18 :          ALLOCATE (krylov_space%c_vec(nspin))
      94            6 :          max_nmo = 0
      95           12 :          DO ispin = 1, nspin
      96            6 :             CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, nao=nao, nmo=nmo)
      97            6 :             CALL cp_fm_create(krylov_space%mo_conv(ispin), mo_coeff%matrix_struct)
      98            6 :             CALL cp_fm_create(krylov_space%mo_refine(ispin), mo_coeff%matrix_struct)
      99            6 :             NULLIFY (fm_struct_tmp)
     100              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=nmo, &
     101              :                                      para_env=mo_coeff%matrix_struct%para_env, &
     102            6 :                                      context=mo_coeff%matrix_struct%context)
     103            6 :             CALL cp_fm_create(krylov_space%chc_mat(ispin), fm_struct_tmp, "chc")
     104            6 :             CALL cp_fm_create(krylov_space%c_vec(ispin), fm_struct_tmp, "vec")
     105            6 :             CALL cp_fm_struct_release(fm_struct_tmp)
     106           18 :             max_nmo = MAX(max_nmo, nmo)
     107              :          END DO
     108              : 
     109              :          !the use of max_nmo might not be ok, in this case allocate nspin matrices
     110           18 :          ALLOCATE (krylov_space%c_eval(max_nmo))
     111              : 
     112           66 :          ALLOCATE (krylov_space%v_mat(nk))
     113              : 
     114            6 :          NULLIFY (fm_struct_tmp)
     115              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nblock, &
     116              :                                   para_env=mo_coeff%matrix_struct%para_env, &
     117            6 :                                   context=mo_coeff%matrix_struct%context)
     118           54 :          DO ik = 1, nk
     119              :             CALL cp_fm_create(krylov_space%v_mat(ik), matrix_struct=fm_struct_tmp, &
     120           54 :                               name="v_mat_"//TRIM(ADJUSTL(cp_to_string(ik))))
     121              :          END DO
     122            6 :          ALLOCATE (krylov_space%tmp_mat)
     123              :          CALL cp_fm_create(krylov_space%tmp_mat, matrix_struct=fm_struct_tmp, &
     124            6 :                            name="tmp_mat")
     125            6 :          CALL cp_fm_struct_release(fm_struct_tmp)
     126              : 
     127              :          ! NOTE: the following matrices are small and could be defined
     128              : !           as standard array rather than distributed fm
     129            6 :          NULLIFY (fm_struct_tmp)
     130              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nblock, ncol_global=nblock, &
     131              :                                   para_env=mo_coeff%matrix_struct%para_env, &
     132            6 :                                   context=mo_coeff%matrix_struct%context)
     133            6 :          ALLOCATE (krylov_space%block1_mat)
     134              :          CALL cp_fm_create(krylov_space%block1_mat, matrix_struct=fm_struct_tmp, &
     135            6 :                            name="a_mat_"//TRIM(ADJUSTL(cp_to_string(ik))))
     136            6 :          ALLOCATE (krylov_space%block2_mat)
     137              :          CALL cp_fm_create(krylov_space%block2_mat, matrix_struct=fm_struct_tmp, &
     138            6 :                            name="b_mat_"//TRIM(ADJUSTL(cp_to_string(ik))))
     139            6 :          ALLOCATE (krylov_space%block3_mat)
     140              :          CALL cp_fm_create(krylov_space%block3_mat, matrix_struct=fm_struct_tmp, &
     141            6 :                            name="b2_mat_"//TRIM(ADJUSTL(cp_to_string(ik))))
     142            6 :          CALL cp_fm_struct_release(fm_struct_tmp)
     143              : 
     144            6 :          ndim = nblock*nk
     145            6 :          NULLIFY (fm_struct_tmp)
     146              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ndim, ncol_global=ndim, &
     147              :                                   para_env=mo_coeff%matrix_struct%para_env, &
     148            6 :                                   context=mo_coeff%matrix_struct%context)
     149            6 :          ALLOCATE (krylov_space%block4_mat)
     150              :          CALL cp_fm_create(krylov_space%block4_mat, matrix_struct=fm_struct_tmp, &
     151            6 :                            name="t_mat")
     152            6 :          ALLOCATE (krylov_space%block5_mat)
     153              :          CALL cp_fm_create(krylov_space%block5_mat, matrix_struct=fm_struct_tmp, &
     154            6 :                            name="t_vec")
     155            6 :          CALL cp_fm_struct_release(fm_struct_tmp)
     156           18 :          ALLOCATE (krylov_space%t_eval(ndim))
     157              : 
     158              :       ELSE
     159              :          !Nothing should be done
     160              :       END IF
     161              : 
     162           10 :       CALL timestop(handle)
     163              : 
     164           10 :    END SUBROUTINE krylov_space_allocate
     165              : 
     166              : ! **************************************************************************************************
     167              : !> \brief lanczos refinement by blocks of non-converged MOs
     168              : !> \param krylov_space ...
     169              : !> \param ks ...
     170              : !> \param c0 ...
     171              : !> \param c1 ...
     172              : !> \param eval ...
     173              : !> \param nao ...
     174              : !> \param eps_iter ...
     175              : !> \param ispin ...
     176              : !> \param check_moconv_only ...
     177              : !> \param
     178              : !> \par History
     179              : !>      05.2009 created [MI]
     180              : ! **************************************************************************************************
     181              : 
     182            0 :    SUBROUTINE lanczos_refinement(krylov_space, ks, c0, c1, eval, nao, &
     183              :                                  eps_iter, ispin, check_moconv_only)
     184              : 
     185              :       TYPE(krylov_space_type), POINTER                   :: krylov_space
     186              :       TYPE(cp_fm_type), INTENT(IN)                       :: ks, c0, c1
     187              :       REAL(dp), DIMENSION(:), POINTER                    :: eval
     188              :       INTEGER, INTENT(IN)                                :: nao
     189              :       REAL(dp), INTENT(IN)                               :: eps_iter
     190              :       INTEGER, INTENT(IN)                                :: ispin
     191              :       LOGICAL, INTENT(IN), OPTIONAL                      :: check_moconv_only
     192              : 
     193              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'lanczos_refinement'
     194              :       REAL(KIND=dp), PARAMETER                           :: rmone = -1.0_dp, rone = 1.0_dp, &
     195              :                                                             rzero = 0.0_dp
     196              : 
     197              :       INTEGER :: hand1, hand2, hand3, hand4, hand5, handle, ib, ik, imo, imo_low, imo_up, it, jt, &
     198              :          nblock, ndim, nmo, nmo_converged, nmo_nc, nmob, num_blocks
     199            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: itaken
     200              :       LOGICAL                                            :: my_check_moconv_only
     201              :       REAL(dp)                                           :: max_norm, min_norm, vmax
     202            0 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: q_mat, tblock, tvblock
     203              :       REAL(dp), DIMENSION(:), POINTER                    :: c_res, t_eval
     204              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     205              :       TYPE(cp_fm_type)                                   :: c2_tmp, c3_tmp, c_tmp, hc
     206            0 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: v_mat
     207              :       TYPE(cp_fm_type), POINTER                          :: a_mat, b2_mat, b_mat, chc, evec, t_mat, &
     208              :                                                             t_vec
     209              : 
     210            0 :       CALL timeset(routineN, handle)
     211              : 
     212            0 :       NULLIFY (fm_struct_tmp)
     213            0 :       NULLIFY (chc, evec)
     214              :       NULLIFY (c_res, t_eval)
     215            0 :       NULLIFY (t_mat, t_vec)
     216            0 :       NULLIFY (a_mat, b_mat, b2_mat, v_mat)
     217              : 
     218            0 :       nmo = SIZE(eval, 1)
     219            0 :       my_check_moconv_only = .FALSE.
     220            0 :       IF (PRESENT(check_moconv_only)) my_check_moconv_only = check_moconv_only
     221              : 
     222            0 :       chc => krylov_space%chc_mat(ispin)
     223            0 :       evec => krylov_space%c_vec(ispin)
     224            0 :       c_res => krylov_space%c_eval
     225            0 :       t_eval => krylov_space%t_eval
     226              : 
     227              :       NULLIFY (fm_struct_tmp)
     228              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo, &
     229              :                                para_env=c0%matrix_struct%para_env, &
     230            0 :                                context=c0%matrix_struct%context)
     231              :       CALL cp_fm_create(c_tmp, matrix_struct=fm_struct_tmp, &
     232            0 :                         name="c_tmp")
     233              :       CALL cp_fm_create(hc, matrix_struct=fm_struct_tmp, &
     234            0 :                         name="hc")
     235            0 :       CALL cp_fm_struct_release(fm_struct_tmp)
     236              : 
     237              :       !Compute (C^t)HC
     238            0 :       CALL parallel_gemm('N', 'N', nao, nmo, nao, rone, ks, c0, rzero, hc)
     239            0 :       CALL parallel_gemm('T', 'N', nmo, nmo, nao, rone, c0, hc, rzero, chc)
     240              : 
     241              :       !Diagonalize  (C^t)HC
     242            0 :       CALL timeset(routineN//"diag_chc", hand1)
     243            0 :       CALL choose_eigv_solver(chc, evec, eval)
     244            0 :       CALL timestop(hand1)
     245              : 
     246              :       !Rotate the C vectors
     247            0 :       CALL parallel_gemm('N', 'N', nao, nmo, nmo, rone, c0, evec, rzero, c1)
     248              : 
     249              :       !Check for converged states
     250            0 :       CALL parallel_gemm('N', 'N', nao, nmo, nmo, rone, hc, evec, rzero, c_tmp)
     251            0 :       CALL cp_fm_to_fm(c1, c0, nmo, 1, 1)
     252            0 :       CALL cp_fm_column_scale(c1, eval)
     253            0 :       CALL cp_fm_scale_and_add(1.0_dp, c_tmp, rmone, c1)
     254            0 :       CALL cp_fm_vectorsnorm(c_tmp, c_res)
     255              : 
     256            0 :       nmo_converged = 0
     257            0 :       nmo_nc = 0
     258            0 :       max_norm = 0.0_dp
     259            0 :       min_norm = 1.e10_dp
     260            0 :       CALL cp_fm_set_all(c1, rzero)
     261            0 :       DO imo = 1, nmo
     262            0 :          max_norm = MAX(max_norm, c_res(imo))
     263            0 :          min_norm = MIN(min_norm, c_res(imo))
     264              :       END DO
     265            0 :       DO imo = 1, nmo
     266            0 :          IF (c_res(imo) <= eps_iter) THEN
     267            0 :             nmo_converged = nmo_converged + 1
     268              :          ELSE
     269            0 :             nmo_nc = nmo - nmo_converged
     270            0 :             EXIT
     271              :          END IF
     272              :       END DO
     273              : 
     274            0 :       nblock = krylov_space%nblock
     275            0 :       num_blocks = nmo_nc/nblock
     276              : 
     277            0 :       krylov_space%nmo_nc = nmo_nc
     278            0 :       krylov_space%nmo_conv = nmo_converged
     279            0 :       krylov_space%max_res_norm = max_norm
     280            0 :       krylov_space%min_res_norm = min_norm
     281              : 
     282            0 :       IF (my_check_moconv_only) THEN
     283            0 :          CALL cp_fm_release(c_tmp)
     284            0 :          CALL cp_fm_release(hc)
     285            0 :          CALL timestop(handle)
     286            0 :          RETURN
     287            0 :       ELSE IF (krylov_space%nmo_nc > 0) THEN
     288              : 
     289            0 :          CALL cp_fm_to_fm(c0, c1, nmo_nc, nmo_converged + 1, 1)
     290              : 
     291            0 :          nblock = krylov_space%nblock
     292            0 :          IF (MODULO(nmo_nc, nblock) > 0.0_dp) THEN
     293            0 :             num_blocks = nmo_nc/nblock + 1
     294              :          ELSE
     295            0 :             num_blocks = nmo_nc/nblock
     296              :          END IF
     297              : 
     298            0 :          DO ib = 1, num_blocks
     299              : 
     300            0 :             imo_low = (ib - 1)*nblock + 1
     301            0 :             imo_up = MIN(ib*nblock, nmo_nc)
     302            0 :             nmob = imo_up - imo_low + 1
     303            0 :             ndim = krylov_space%nkrylov*nmob
     304              : 
     305            0 :             NULLIFY (fm_struct_tmp)
     306              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=ndim, &
     307              :                                      para_env=c0%matrix_struct%para_env, &
     308            0 :                                      context=c0%matrix_struct%context)
     309              :             CALL cp_fm_create(c2_tmp, matrix_struct=fm_struct_tmp, &
     310            0 :                               name="c2_tmp")
     311            0 :             CALL cp_fm_struct_release(fm_struct_tmp)
     312            0 :             NULLIFY (fm_struct_tmp)
     313              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmob, ncol_global=ndim, &
     314              :                                      para_env=c0%matrix_struct%para_env, &
     315            0 :                                      context=c0%matrix_struct%context)
     316              :             CALL cp_fm_create(c3_tmp, matrix_struct=fm_struct_tmp, &
     317            0 :                               name="c3_tmp")
     318            0 :             CALL cp_fm_struct_release(fm_struct_tmp)
     319              : 
     320              :             ! Create local matrix of right size
     321            0 :             IF (nmob /= nblock) THEN
     322            0 :                NULLIFY (a_mat, b_mat, b2_mat, t_mat, t_vec, v_mat)
     323            0 :                ALLOCATE (a_mat, b_mat, b2_mat, t_mat, t_vec)
     324            0 :                NULLIFY (fm_struct_tmp)
     325              :                CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmob, ncol_global=nmob, &
     326              :                                         para_env=chc%matrix_struct%para_env, &
     327            0 :                                         context=chc%matrix_struct%context)
     328              :                CALL cp_fm_create(a_mat, matrix_struct=fm_struct_tmp, &
     329            0 :                                  name="a_mat")
     330              :                CALL cp_fm_create(b_mat, matrix_struct=fm_struct_tmp, &
     331            0 :                                  name="b_mat")
     332              :                CALL cp_fm_create(b2_mat, matrix_struct=fm_struct_tmp, &
     333            0 :                                  name="b2_mat")
     334            0 :                CALL cp_fm_struct_release(fm_struct_tmp)
     335            0 :                NULLIFY (fm_struct_tmp)
     336              :                CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ndim, ncol_global=ndim, &
     337              :                                         para_env=chc%matrix_struct%para_env, &
     338            0 :                                         context=chc%matrix_struct%context)
     339              :                CALL cp_fm_create(t_mat, matrix_struct=fm_struct_tmp, &
     340            0 :                                  name="t_mat")
     341              :                CALL cp_fm_create(t_vec, matrix_struct=fm_struct_tmp, &
     342            0 :                                  name="t_vec")
     343            0 :                CALL cp_fm_struct_release(fm_struct_tmp)
     344            0 :                NULLIFY (fm_struct_tmp)
     345              :                CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmob, &
     346              :                                         para_env=c0%matrix_struct%para_env, &
     347            0 :                                         context=c0%matrix_struct%context)
     348            0 :                ALLOCATE (v_mat(krylov_space%nkrylov))
     349            0 :                DO ik = 1, krylov_space%nkrylov
     350              :                   CALL cp_fm_create(v_mat(ik), matrix_struct=fm_struct_tmp, &
     351            0 :                                     name="v_mat")
     352              :                END DO
     353            0 :                CALL cp_fm_struct_release(fm_struct_tmp)
     354              :             ELSE
     355            0 :                a_mat => krylov_space%block1_mat
     356            0 :                b_mat => krylov_space%block2_mat
     357            0 :                b2_mat => krylov_space%block3_mat
     358            0 :                t_mat => krylov_space%block4_mat
     359            0 :                t_vec => krylov_space%block5_mat
     360            0 :                v_mat => krylov_space%v_mat
     361              :             END IF
     362              : 
     363            0 :             ALLOCATE (tblock(nmob, nmob))
     364            0 :             ALLOCATE (tvblock(nmob, ndim))
     365              : 
     366            0 :             CALL timeset(routineN//"_kry_loop", hand2)
     367            0 :             CALL cp_fm_set_all(b_mat, rzero)
     368            0 :             CALL cp_fm_set_all(t_mat, rzero)
     369            0 :             CALL cp_fm_to_fm(c1, v_mat(1), nmob, imo_low, 1)
     370              : 
     371              :             !Compute A =(V^t)HV
     372            0 :             CALL parallel_gemm('N', 'N', nao, nmob, nao, rone, ks, v_mat(1), rzero, hc)
     373              :             CALL parallel_gemm('T', 'N', nmob, nmob, nao, rone, v_mat(1), hc, &
     374            0 :                                rzero, a_mat)
     375              : 
     376              :             !Compute the residual matrix R for next
     377              :             !factorisation
     378              :             CALL parallel_gemm('N', 'N', nao, nmob, nmob, rone, v_mat(1), a_mat, &
     379            0 :                                rzero, c_tmp)
     380            0 :             CALL cp_fm_scale_and_add(rmone, c_tmp, rone, hc)
     381              : 
     382              :             ! Build the block tridiagonal matrix
     383            0 :             CALL cp_fm_get_submatrix(a_mat, tblock, 1, 1, nmob, nmob)
     384            0 :             CALL cp_fm_set_submatrix(t_mat, tblock, 1, 1, nmob, nmob)
     385              : 
     386            0 :             DO ik = 2, krylov_space%nkrylov
     387              : 
     388              :                ! Call lapack for QR factorization
     389            0 :                CALL cp_fm_set_all(b_mat, rzero)
     390            0 :                CALL cp_fm_to_fm(c_tmp, v_mat(ik), nmob, 1, 1)
     391            0 :                CALL cp_fm_qr_factorization(c_tmp, b_mat, nao, nmob, 1, 1)
     392              : 
     393              :                CALL cp_fm_triangular_multiply(b_mat, v_mat(ik), side="R", invert_tr=.TRUE., &
     394            0 :                                               n_rows=nao, n_cols=nmob)
     395              : 
     396              :                !Compute A =(V^t)HV
     397            0 :                CALL parallel_gemm('N', 'N', nao, nmob, nao, rone, ks, v_mat(ik), rzero, hc)
     398            0 :                CALL parallel_gemm('T', 'N', nmob, nmob, nao, rone, v_mat(ik), hc, rzero, a_mat)
     399              : 
     400              :                !Compute the !residual matrix R !for next !factorisation
     401              :                CALL parallel_gemm('N', 'N', nao, nmob, nmob, rone, v_mat(ik), a_mat, &
     402            0 :                                   rzero, c_tmp)
     403            0 :                CALL cp_fm_scale_and_add(rmone, c_tmp, rone, hc)
     404            0 :                CALL cp_fm_to_fm(v_mat(ik - 1), hc, nmob, 1, 1)
     405              :                CALL cp_fm_triangular_multiply(b_mat, hc, side='R', transpose_tr=.TRUE., &
     406            0 :                                               n_rows=nao, n_cols=nmob, alpha=rmone)
     407            0 :                CALL cp_fm_scale_and_add(rone, c_tmp, rone, hc)
     408              : 
     409              :                ! Build the block tridiagonal matrix
     410            0 :                it = (ik - 2)*nmob + 1
     411            0 :                jt = (ik - 1)*nmob + 1
     412              : 
     413            0 :                CALL cp_fm_get_submatrix(a_mat, tblock, 1, 1, nmob, nmob)
     414            0 :                CALL cp_fm_set_submatrix(t_mat, tblock, jt, jt, nmob, nmob)
     415            0 :                CALL cp_fm_transpose(b_mat, a_mat)
     416            0 :                CALL cp_fm_get_submatrix(a_mat, tblock, 1, 1, nmob, nmob)
     417            0 :                CALL cp_fm_set_submatrix(t_mat, tblock, it, jt, nmob, nmob)
     418              : 
     419              :             END DO ! ik
     420            0 :             CALL timestop(hand2)
     421              : 
     422            0 :             DEALLOCATE (tblock)
     423              : 
     424            0 :             CALL timeset(routineN//"_diag_tri", hand3)
     425              : 
     426            0 :             CALL choose_eigv_solver(t_mat, t_vec, t_eval)
     427              :             ! Diagonalize the block-tridiagonal matrix
     428            0 :             CALL timestop(hand3)
     429              : 
     430            0 :             CALL timeset(routineN//"_build_cnew", hand4)
     431              : !        !Compute the refined vectors
     432            0 :             CALL cp_fm_set_all(c2_tmp, rzero)
     433            0 :             DO ik = 1, krylov_space%nkrylov
     434            0 :                jt = (ik - 1)*nmob
     435              :                CALL parallel_gemm('N', 'N', nao, ndim, nmob, rone, v_mat(ik), t_vec, rone, c2_tmp, &
     436            0 :                                   b_first_row=(jt + 1))
     437              :             END DO
     438            0 :             DEALLOCATE (tvblock)
     439              : 
     440            0 :             CALL cp_fm_set_all(c3_tmp, rzero)
     441            0 :             CALL parallel_gemm('T', 'N', nmob, ndim, nao, rone, v_mat(1), c2_tmp, rzero, c3_tmp)
     442              : 
     443              :             !Try to avoid linear dependencies
     444            0 :             ALLOCATE (q_mat(nmob, ndim))
     445              :             !get max
     446            0 :             CALL cp_fm_get_submatrix(c3_tmp, q_mat, 1, 1, nmob, ndim)
     447              : 
     448            0 :             ALLOCATE (itaken(ndim))
     449            0 :             itaken = 0
     450            0 :             DO it = 1, nmob
     451            0 :                vmax = 0.0_dp
     452            0 :                ik = 0
     453              :                !select index ik
     454            0 :                DO jt = 1, ndim
     455            0 :                   IF (itaken(jt) == 0 .AND. ABS(q_mat(it, jt)) > vmax) THEN
     456            0 :                      vmax = ABS(q_mat(it, jt))
     457            0 :                      ik = jt
     458              :                   END IF
     459              :                END DO
     460            0 :                IF (ik == 0) CYCLE ! all candidates NaN or zero: keep the entry vector
     461            0 :                itaken(ik) = 1
     462              : 
     463            0 :                CALL cp_fm_to_fm(c2_tmp, v_mat(1), 1, ik, it)
     464              :             END DO
     465            0 :             DEALLOCATE (itaken)
     466            0 :             DEALLOCATE (q_mat)
     467              : 
     468              :             !Copy in the converged set to enlarge the converged subspace
     469            0 :             CALL cp_fm_to_fm(v_mat(1), c0, nmob, 1, (nmo_converged + imo_low))
     470            0 :             CALL timestop(hand4)
     471              : 
     472            0 :             IF (nmob < nblock) THEN
     473            0 :                CALL cp_fm_release(a_mat)
     474            0 :                CALL cp_fm_release(b_mat)
     475            0 :                CALL cp_fm_release(b2_mat)
     476            0 :                CALL cp_fm_release(t_mat)
     477            0 :                CALL cp_fm_release(t_vec)
     478            0 :                DEALLOCATE (a_mat, b_mat, b2_mat, t_mat, t_vec)
     479            0 :                CALL cp_fm_release(v_mat)
     480              :             END IF
     481            0 :             CALL cp_fm_release(c2_tmp)
     482            0 :             CALL cp_fm_release(c3_tmp)
     483              :          END DO ! ib
     484              : 
     485            0 :          CALL timeset(routineN//"_ortho", hand5)
     486            0 :          CALL parallel_gemm('T', 'N', nmo, nmo, nao, rone, c0, c0, rzero, chc)
     487              : 
     488            0 :          CALL cp_fm_cholesky_decompose(chc, nmo)
     489            0 :          CALL cp_fm_triangular_multiply(chc, c0, 'R', invert_tr=.TRUE.)
     490            0 :          CALL timestop(hand5)
     491              : 
     492            0 :          CALL cp_fm_release(c_tmp)
     493            0 :          CALL cp_fm_release(hc)
     494              :       ELSE
     495            0 :          CALL cp_fm_release(c_tmp)
     496            0 :          CALL cp_fm_release(hc)
     497            0 :          CALL timestop(handle)
     498            0 :          RETURN
     499              :       END IF
     500              : 
     501            0 :       CALL timestop(handle)
     502              : 
     503            0 :    END SUBROUTINE lanczos_refinement
     504              : 
     505              : !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     506              : 
     507              : ! **************************************************************************************************
     508              : !> \brief ...
     509              : !> \param krylov_space ...
     510              : !> \param ks ...
     511              : !> \param c0 ...
     512              : !> \param c1 ...
     513              : !> \param eval ...
     514              : !> \param nao ...
     515              : !> \param eps_iter ...
     516              : !> \param ispin ...
     517              : !> \param check_moconv_only ...
     518              : ! **************************************************************************************************
     519          744 :    SUBROUTINE lanczos_refinement_2v(krylov_space, ks, c0, c1, eval, nao, &
     520              :                                     eps_iter, ispin, check_moconv_only)
     521              : 
     522              :       TYPE(krylov_space_type), POINTER                   :: krylov_space
     523              :       TYPE(cp_fm_type), INTENT(IN)                       :: ks, c0, c1
     524              :       REAL(dp), DIMENSION(:), POINTER                    :: eval
     525              :       INTEGER, INTENT(IN)                                :: nao
     526              :       REAL(dp), INTENT(IN)                               :: eps_iter
     527              :       INTEGER, INTENT(IN)                                :: ispin
     528              :       LOGICAL, INTENT(IN), OPTIONAL                      :: check_moconv_only
     529              : 
     530              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'lanczos_refinement_2v'
     531              :       REAL(KIND=dp), PARAMETER                           :: rmone = -1.0_dp, rone = 1.0_dp, &
     532              :                                                             rzero = 0.0_dp
     533              : 
     534              :       INTEGER :: hand1, hand2, hand3, hand4, hand5, hand6, handle, i, ia, ib, ik, imo, imo_low, &
     535              :          imo_up, info, it, j, jt, liwork, lwork, nblock, ndim, nmo, nmo_converged, nmo_nc, nmob, &
     536              :          num_blocks
     537          744 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: itaken
     538          744 :       INTEGER, DIMENSION(:), POINTER                     :: iwork
     539              :       LOGICAL                                            :: my_check_moconv_only
     540              :       REAL(dp)                                           :: max_norm, min_norm, vmax
     541          744 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: a_block, b_block, q_mat, t_mat
     542          744 :       REAL(dp), DIMENSION(:), POINTER                    :: c_res, t_eval
     543          744 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: work
     544          744 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: a_loc, b_loc
     545              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     546              :       TYPE(cp_fm_type)                                   :: b_mat, c2_tmp, c_tmp, hc, v_tmp
     547          744 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: v_mat
     548              :       TYPE(cp_fm_type), POINTER                          :: chc, evec
     549              : 
     550          744 :       CALL timeset(routineN, handle)
     551              : 
     552          744 :       NULLIFY (fm_struct_tmp)
     553          744 :       NULLIFY (chc, evec)
     554          744 :       NULLIFY (c_res, t_eval)
     555          744 :       NULLIFY (b_loc, a_loc)
     556              : 
     557          744 :       nmo = SIZE(eval, 1)
     558          744 :       my_check_moconv_only = .FALSE.
     559          744 :       IF (PRESENT(check_moconv_only)) my_check_moconv_only = check_moconv_only
     560              : 
     561          744 :       chc => krylov_space%chc_mat(ispin)
     562          744 :       evec => krylov_space%c_vec(ispin)
     563          744 :       c_res => krylov_space%c_eval
     564          744 :       t_eval => krylov_space%t_eval
     565              : 
     566              :       NULLIFY (fm_struct_tmp)
     567              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo, &
     568              :                                para_env=c0%matrix_struct%para_env, &
     569          744 :                                context=c0%matrix_struct%context)
     570              :       CALL cp_fm_create(c_tmp, matrix_struct=fm_struct_tmp, &
     571          744 :                         name="c_tmp")
     572              :       CALL cp_fm_create(hc, matrix_struct=fm_struct_tmp, &
     573          744 :                         name="hc")
     574          744 :       CALL cp_fm_struct_release(fm_struct_tmp)
     575              : 
     576              :       !Compute (C^t)HC
     577          744 :       CALL parallel_gemm('N', 'N', nao, nmo, nao, rone, ks, c0, rzero, hc)
     578          744 :       CALL parallel_gemm('T', 'N', nmo, nmo, nao, rone, c0, hc, rzero, chc)
     579              : 
     580              :       !Diagonalize  (C^t)HC
     581          744 :       CALL timeset(routineN//"diag_chc", hand1)
     582          744 :       CALL choose_eigv_solver(chc, evec, eval)
     583              : 
     584          744 :       CALL timestop(hand1)
     585              : 
     586          744 :       CALL timeset(routineN//"check_conv", hand6)
     587              :       !Rotate the C vectors
     588          744 :       CALL parallel_gemm('N', 'N', nao, nmo, nmo, rone, c0, evec, rzero, c1)
     589              : 
     590              :       !Check for converged states
     591          744 :       CALL parallel_gemm('N', 'N', nao, nmo, nmo, rone, hc, evec, rzero, c_tmp)
     592          744 :       CALL cp_fm_to_fm(c1, c0, nmo, 1, 1)
     593          744 :       CALL cp_fm_column_scale(c1, eval)
     594          744 :       CALL cp_fm_scale_and_add(1.0_dp, c_tmp, rmone, c1)
     595          744 :       CALL cp_fm_vectorsnorm(c_tmp, c_res)
     596              : 
     597          744 :       nmo_converged = 0
     598          744 :       nmo_nc = 0
     599          744 :       max_norm = 0.0_dp
     600          744 :       min_norm = 1.e10_dp
     601          744 :       CALL cp_fm_set_all(c1, rzero)
     602        24792 :       DO imo = 1, nmo
     603        24048 :          max_norm = MAX(max_norm, c_res(imo))
     604        24792 :          min_norm = MIN(min_norm, c_res(imo))
     605              :       END DO
     606        19970 :       DO imo = 1, nmo
     607        19970 :          IF (c_res(imo) <= eps_iter) THEN
     608        19226 :             nmo_converged = nmo_converged + 1
     609              :          ELSE
     610          734 :             nmo_nc = nmo - nmo_converged
     611          734 :             EXIT
     612              :          END IF
     613              :       END DO
     614          744 :       CALL timestop(hand6)
     615              : 
     616          744 :       CALL cp_fm_release(c_tmp)
     617          744 :       CALL cp_fm_release(hc)
     618              : 
     619          744 :       krylov_space%nmo_nc = nmo_nc
     620          744 :       krylov_space%nmo_conv = nmo_converged
     621          744 :       krylov_space%max_res_norm = max_norm
     622          744 :       krylov_space%min_res_norm = min_norm
     623              : 
     624          744 :       IF (my_check_moconv_only) THEN
     625              :          ! Do nothing
     626          744 :       ELSE IF (krylov_space%nmo_nc > 0) THEN
     627              : 
     628          734 :          CALL cp_fm_to_fm(c0, c1, nmo_nc, nmo_converged + 1, 1)
     629              : 
     630          734 :          nblock = krylov_space%nblock
     631          734 :          IF (MODULO(nmo_nc, nblock) > 0.0_dp) THEN
     632          100 :             num_blocks = nmo_nc/nblock + 1
     633              :          ELSE
     634          634 :             num_blocks = nmo_nc/nblock
     635              :          END IF
     636              : 
     637         4062 :          DO ib = 1, num_blocks
     638              : 
     639         3328 :             imo_low = (ib - 1)*nblock + 1
     640         3328 :             imo_up = MIN(ib*nblock, nmo_nc)
     641         3328 :             nmob = imo_up - imo_low + 1
     642         3328 :             ndim = krylov_space%nkrylov*nmob
     643              : 
     644              :             ! Allocation
     645         3328 :             CALL timeset(routineN//"alloc", hand6)
     646        13312 :             ALLOCATE (a_block(nmob, nmob))
     647         9984 :             ALLOCATE (b_block(nmob, nmob))
     648        13312 :             ALLOCATE (t_mat(ndim, ndim))
     649              : 
     650         3328 :             NULLIFY (fm_struct_tmp)
     651              :             ! by forcing ncol_block=nmo, the needed part of the matrix is distributed on a subset of processes
     652              :             ! this is due to the use of two-dimensional grids of processes
     653              :             ! nrow_global is distributed over num_pe(1)
     654              :             ! a local_data array is anyway allocated for the processes non included
     655              :             ! this should have a minimum size
     656              :             ! with ncol_local=1.
     657              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmob, &
     658              :                                      ncol_block=nmob, &
     659              :                                      para_env=c0%matrix_struct%para_env, &
     660              :                                      context=c0%matrix_struct%context, &
     661         3328 :                                      force_block=.TRUE.)
     662              :             CALL cp_fm_create(c_tmp, matrix_struct=fm_struct_tmp, &
     663         3328 :                               name="c_tmp")
     664         3328 :             CALL cp_fm_set_all(c_tmp, rzero)
     665              :             CALL cp_fm_create(v_tmp, matrix_struct=fm_struct_tmp, &
     666         3328 :                               name="v_tmp")
     667         3328 :             CALL cp_fm_set_all(v_tmp, rzero)
     668         3328 :             CALL cp_fm_struct_release(fm_struct_tmp)
     669         3328 :             NULLIFY (fm_struct_tmp)
     670        36608 :             ALLOCATE (v_mat(krylov_space%nkrylov))
     671              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmob, &
     672              :                                      ncol_block=nmob, &
     673              :                                      para_env=c0%matrix_struct%para_env, &
     674              :                                      context=c0%matrix_struct%context, &
     675         3328 :                                      force_block=.TRUE.)
     676        29952 :             DO ik = 1, krylov_space%nkrylov
     677              :                CALL cp_fm_create(v_mat(ik), matrix_struct=fm_struct_tmp, &
     678        29952 :                                  name="v_mat", set_zero=.TRUE.)
     679              :             END DO
     680              :             CALL cp_fm_create(hc, matrix_struct=fm_struct_tmp, &
     681         3328 :                               name="hc", set_zero=.TRUE.)
     682         3328 :             CALL cp_fm_struct_release(fm_struct_tmp)
     683         3328 :             NULLIFY (fm_struct_tmp)
     684              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=ndim, &
     685              :                                      ncol_block=ndim, &
     686              :                                      para_env=c0%matrix_struct%para_env, &
     687              :                                      context=c0%matrix_struct%context, &
     688         3328 :                                      force_block=.TRUE.)
     689              :             CALL cp_fm_create(c2_tmp, matrix_struct=fm_struct_tmp, &
     690         3328 :                               name="c2_tmp")
     691         3328 :             CALL cp_fm_struct_release(fm_struct_tmp)
     692              : 
     693         3328 :             NULLIFY (fm_struct_tmp)
     694              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmob, ncol_global=nmob, &
     695              :                                      para_env=c0%matrix_struct%para_env, &
     696         3328 :                                      context=c0%matrix_struct%context)
     697              :             CALL cp_fm_create(b_mat, matrix_struct=fm_struct_tmp, &
     698         3328 :                               name="b_mat")
     699         3328 :             CALL cp_fm_struct_release(fm_struct_tmp)
     700         3328 :             CALL timestop(hand6)
     701              :             !End allocation
     702              : 
     703         3328 :             CALL cp_fm_set_all(b_mat, rzero)
     704         3328 :             CALL cp_fm_to_fm(c1, v_mat(1), nmob, imo_low, 1)
     705              : 
     706              :             ! Here starts the construction of krylov space
     707         3328 :             CALL timeset(routineN//"_kry_loop", hand2)
     708              :             !Compute A =(V^t)HV
     709         3328 :             CALL parallel_gemm('N', 'N', nao, nmob, nao, rone, ks, v_mat(1), rzero, hc)
     710              : 
     711         3328 :             a_block = 0.0_dp
     712         3328 :             a_loc => v_mat(1)%local_data
     713         3328 :             b_loc => hc%local_data
     714              : 
     715         3328 :             IF (SIZE(hc%local_data, 2) == nmob) THEN
     716              :                ! this is a work around to avoid problems due to the two dimensional grid of processes
     717              :                CALL dgemm('T', 'N', nmob, nmob, SIZE(hc%local_data, 1), 1.0_dp, a_loc(1, 1), &
     718         3328 :                           SIZE(hc%local_data, 1), b_loc(1, 1), SIZE(hc%local_data, 1), 0.0_dp, a_block(1, 1), nmob)
     719              :             END IF
     720         3328 :             CALL hc%matrix_struct%para_env%sum(a_block)
     721              : 
     722              :             !Compute the residual matrix R for next
     723              :             !factorisation
     724       206313 :             c_tmp%local_data = 0.0_dp
     725         3328 :             IF (SIZE(c_tmp%local_data, 2) == nmob) THEN
     726         3328 :                b_loc => c_tmp%local_data
     727              :                CALL dgemm('N', 'N', SIZE(c_tmp%local_data, 1), nmob, nmob, 1.0_dp, a_loc(1, 1), &
     728              :                           SIZE(c_tmp%local_data, 1), a_block(1, 1), nmob, 0.0_dp, &
     729         3328 :                           b_loc(1, 1), SIZE(c_tmp%local_data, 1))
     730              :             END IF
     731         3328 :             CALL cp_fm_scale_and_add(rmone, c_tmp, rone, hc)
     732              : 
     733              :             ! Build the block tridiagonal matrix
     734         3328 :             t_mat = 0.0_dp
     735         8150 :             DO i = 1, nmob
     736        18772 :                t_mat(1:nmob, i) = a_block(1:nmob, i)
     737              :             END DO
     738              : 
     739        26624 :             DO ik = 2, krylov_space%nkrylov
     740              :                ! Call lapack for QR factorization
     741        23296 :                CALL cp_fm_set_all(b_mat, rzero)
     742        23296 :                CALL cp_fm_to_fm(c_tmp, v_mat(ik), nmob, 1, 1)
     743        23296 :                CALL cp_fm_qr_factorization(c_tmp, b_mat, nao, nmob, 1, 1)
     744              : 
     745              :                CALL cp_fm_triangular_multiply(b_mat, v_mat(ik), side="R", invert_tr=.TRUE., &
     746        23296 :                                               n_rows=nao, n_cols=nmob)
     747              : 
     748        23296 :                CALL cp_fm_get_submatrix(b_mat, b_block, 1, 1, nmob, nmob)
     749              : 
     750              :                !Compute A =(V^t)HV
     751        23296 :                CALL parallel_gemm('N', 'N', nao, nmob, nao, rone, ks, v_mat(ik), rzero, hc)
     752              : 
     753        23296 :                a_block = 0.0_dp
     754        23296 :                IF (SIZE(hc%local_data, 2) == nmob) THEN
     755        23296 :                   a_loc => v_mat(ik)%local_data
     756        23296 :                   b_loc => hc%local_data
     757              :                   CALL dgemm('T', 'N', nmob, nmob, SIZE(hc%local_data, 1), 1.0_dp, a_loc(1, 1), &
     758        23296 :                              SIZE(hc%local_data, 1), b_loc(1, 1), SIZE(hc%local_data, 1), 0.0_dp, a_block(1, 1), nmob)
     759              :                END IF
     760        23296 :                CALL hc%matrix_struct%para_env%sum(a_block)
     761              : 
     762              :                !Compute the residual matrix R for next
     763              :                !factorisation
     764      1444191 :                c_tmp%local_data = 0.0_dp
     765        23296 :                IF (SIZE(c_tmp%local_data, 2) == nmob) THEN
     766        23296 :                   a_loc => v_mat(ik)%local_data
     767        23296 :                   b_loc => c_tmp%local_data
     768              :                   CALL dgemm('N', 'N', SIZE(c_tmp%local_data, 1), nmob, nmob, 1.0_dp, a_loc(1, 1), &
     769              :                              SIZE(c_tmp%local_data, 1), a_block(1, 1), nmob, 0.0_dp, &
     770        23296 :                              b_loc(1, 1), SIZE(c_tmp%local_data, 1))
     771              :                END IF
     772        23296 :                CALL cp_fm_scale_and_add(rmone, c_tmp, rone, hc)
     773              : 
     774        23296 :                IF (SIZE(c_tmp%local_data, 2) == nmob) THEN
     775        23296 :                   a_loc => v_mat(ik - 1)%local_data
     776        57050 :                   DO j = 1, nmob
     777       111104 :                      DO i = 1, j
     778      2012899 :                         DO ia = 1, SIZE(c_tmp%local_data, 1)
     779      1979145 :                            b_loc(ia, i) = b_loc(ia, i) - a_loc(ia, j)*b_block(i, j)
     780              :                         END DO
     781              :                      END DO
     782              :                   END DO
     783              :                END IF
     784              : 
     785              :                ! Build the block tridiagonal matrix
     786        23296 :                it = (ik - 2)*nmob
     787        23296 :                jt = (ik - 1)*nmob
     788        60378 :                DO j = 1, nmob
     789       108108 :                   t_mat(jt + 1:jt + nmob, jt + j) = a_block(1:nmob, j)
     790       131404 :                   DO i = 1, nmob
     791        74354 :                      t_mat(it + i, jt + j) = b_block(j, i)
     792       108108 :                      t_mat(jt + j, it + i) = b_block(j, i)
     793              :                   END DO
     794              :                END DO
     795              :             END DO ! ik
     796         3328 :             CALL timestop(hand2)
     797              : 
     798         3328 :             CALL timeset(routineN//"_diag_tri", hand3)
     799         3328 :             lwork = 1 + 6*ndim + 2*ndim**2 + 5000
     800         3328 :             liwork = 5*ndim + 3
     801         9984 :             ALLOCATE (work(lwork))
     802         9984 :             ALLOCATE (iwork(liwork))
     803              : 
     804              :             ! Diagonalize the block-tridiagonal matrix
     805              :             CALL dsyevd('V', 'U', ndim, t_mat(1, 1), ndim, t_eval(1), &
     806         3328 :                         work(1), lwork, iwork(1), liwork, info)
     807         3328 :             DEALLOCATE (work)
     808         3328 :             DEALLOCATE (iwork)
     809         3328 :             CALL timestop(hand3)
     810              : 
     811         3328 :             CALL timeset(routineN//"_build_cnew", hand4)
     812              : !        !Compute the refined vectors
     813              : 
     814      1627208 :             c2_tmp%local_data = 0.0_dp
     815        13312 :             ALLOCATE (q_mat(nmob, ndim))
     816         3328 :             q_mat = 0.0_dp
     817         3328 :             b_loc => c2_tmp%local_data
     818        29952 :             DO ik = 1, krylov_space%nkrylov
     819        26624 :                CALL cp_fm_to_fm(v_mat(ik), v_tmp, nmob, 1, 1)
     820        29952 :                IF (SIZE(c2_tmp%local_data, 2) == ndim) THEN
     821              : !            a_loc => v_mat(ik)%local_data
     822        26624 :                   a_loc => v_tmp%local_data
     823        26624 :                   it = (ik - 1)*nmob
     824              :                   CALL dgemm('N', 'N', SIZE(c2_tmp%local_data, 1), ndim, nmob, 1.0_dp, a_loc(1, 1), &
     825              :                              SIZE(c2_tmp%local_data, 1), t_mat(it + 1, 1), ndim, 1.0_dp, &
     826        26624 :                              b_loc(1, 1), SIZE(c2_tmp%local_data, 1))
     827              :                END IF
     828              :             END DO !ik
     829              : 
     830              :             !Try to avoid linear dependencies
     831         3328 :             CALL cp_fm_to_fm(v_mat(1), v_tmp, nmob, 1, 1)
     832         3328 :             IF (SIZE(c2_tmp%local_data, 2) == ndim) THEN
     833              : !          a_loc => v_mat(1)%local_data
     834         3328 :                a_loc => v_tmp%local_data
     835         3328 :                b_loc => c2_tmp%local_data
     836              :                CALL dgemm('T', 'N', nmob, ndim, SIZE(v_tmp%local_data, 1), 1.0_dp, a_loc(1, 1), &
     837              :                           SIZE(v_tmp%local_data, 1), b_loc(1, 1), SIZE(v_tmp%local_data, 1), &
     838         3328 :                           0.0_dp, q_mat(1, 1), nmob)
     839              :             END IF
     840         3328 :             CALL hc%matrix_struct%para_env%sum(q_mat)
     841              : 
     842         9984 :             ALLOCATE (itaken(ndim))
     843         3328 :             itaken = 0
     844         8150 :             DO it = 1, nmob
     845         4822 :                vmax = 0.0_dp
     846         4822 :                ik = 0
     847              :                !select index ik
     848        89798 :                DO jt = 1, ndim
     849        89798 :                   IF (itaken(jt) == 0 .AND. ABS(q_mat(it, jt)) > vmax) THEN
     850        11064 :                      vmax = ABS(q_mat(it, jt))
     851        11064 :                      ik = jt
     852              :                   END IF
     853              :                END DO
     854         4822 :                IF (ik == 0) CYCLE ! all candidates NaN or zero: keep the entry vector
     855         4822 :                itaken(ik) = 1
     856              : 
     857         8150 :                CALL cp_fm_to_fm(c2_tmp, v_mat(1), 1, ik, it)
     858              :             END DO
     859         3328 :             DEALLOCATE (itaken)
     860         3328 :             DEALLOCATE (q_mat)
     861              : 
     862              :             !Copy in the converged set to enlarge the converged subspace
     863         3328 :             CALL cp_fm_to_fm(v_mat(1), c0, nmob, 1, (nmo_converged + imo_low))
     864         3328 :             CALL timestop(hand4)
     865              : 
     866         3328 :             CALL cp_fm_release(c2_tmp)
     867         3328 :             CALL cp_fm_release(c_tmp)
     868         3328 :             CALL cp_fm_release(hc)
     869         3328 :             CALL cp_fm_release(v_tmp)
     870         3328 :             CALL cp_fm_release(b_mat)
     871              : 
     872         3328 :             DEALLOCATE (t_mat)
     873         3328 :             DEALLOCATE (a_block)
     874         3328 :             DEALLOCATE (b_block)
     875              : 
     876        30686 :             CALL cp_fm_release(v_mat)
     877              : 
     878              :          END DO ! ib
     879              : 
     880          734 :          CALL timeset(routineN//"_ortho", hand5)
     881          734 :          CALL parallel_gemm('T', 'N', nmo, nmo, nao, rone, c0, c0, rzero, chc)
     882              : 
     883          734 :          CALL cp_fm_cholesky_decompose(chc, nmo)
     884          734 :          CALL cp_fm_triangular_multiply(chc, c0, 'R', invert_tr=.TRUE.)
     885          734 :          CALL timestop(hand5)
     886              :       ELSE
     887              :          ! Do nothing
     888              :       END IF
     889              : 
     890          744 :       CALL timestop(handle)
     891         1488 :    END SUBROUTINE lanczos_refinement_2v
     892              : 
     893              : END MODULE qs_scf_lanczos
        

Generated by: LCOV version 2.0-1