LCOV - code coverage report
Current view: top level - src/arnoldi - arnoldi_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 99.7 % 293 292
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 12 12

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief methods for arnoldi iteration
      10              : !> \par History
      11              : !>       2014.09 created [Florian Schiffmann]
      12              : !>       2023.12 Removed support for single-precision [Ole Schuett]
      13              : !>       2024.12 Removed support for complex input matrices [Ole Schuett]
      14              : !> \author Florian Schiffmann
      15              : ! **************************************************************************************************
      16              : MODULE arnoldi_methods
      17              :    USE arnoldi_geev,                    ONLY: arnoldi_general_local_diag,&
      18              :                                               arnoldi_symm_local_diag,&
      19              :                                               arnoldi_tridiag_local_diag
      20              :    USE arnoldi_types,                   ONLY: arnoldi_control_type,&
      21              :                                               arnoldi_data_type,&
      22              :                                               arnoldi_env_type,&
      23              :                                               get_control,&
      24              :                                               get_data,&
      25              :                                               m_x_v_vectors_type
      26              :    USE arnoldi_vector,                  ONLY: dbcsr_matrix_colvec_multiply
      27              :    USE cp_dbcsr_api,                    ONLY: &
      28              :         dbcsr_add, dbcsr_copy, dbcsr_get_data_p, dbcsr_get_info, dbcsr_iterator_blocks_left, &
      29              :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      30              :         dbcsr_p_type, dbcsr_scale, dbcsr_type
      31              :    USE kinds,                           ONLY: dp
      32              :    USE message_passing,                 ONLY: mp_comm_type
      33              : #include "../base/base_uses.f90"
      34              : 
      35              :    IMPLICIT NONE
      36              : 
      37              :    PRIVATE
      38              : 
      39              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'arnoldi_methods'
      40              : 
      41              :    PUBLIC :: arnoldi_init, build_subspace, compute_evals, arnoldi_iram, &
      42              :              gev_arnoldi_init, gev_build_subspace, gev_update_data
      43              : 
      44              : CONTAINS
      45              : 
      46              : ! **************************************************************************************************
      47              : !> \brief Alogorithm for the implicit restarts in the arnoldi method
      48              : !>        this is an early implementation which scales subspace size^4
      49              : !>        by replacing the lapack calls with direct math the
      50              : !>        QR and  gemms can be made linear and a N^2 sacling will be acchieved
      51              : !>        however this already sets the framework but should be used with care.
      52              : !>        Currently all based on lapack.
      53              : !> \param arnoldi_env ...
      54              : ! **************************************************************************************************
      55          260 :    SUBROUTINE arnoldi_iram(arnoldi_env)
      56              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
      57              : 
      58              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'arnoldi_iram'
      59              : 
      60          260 :       COMPLEX(dp), ALLOCATABLE, DIMENSION(:)             :: tau, work, work_measure
      61          260 :       COMPLEX(dp), ALLOCATABLE, DIMENSION(:, :)          :: Q, safe_mat, tmp_mat, tmp_mat1
      62              :       INTEGER                                            :: handle, i, info, j, lwork, msize, nwant
      63              :       REAL(kind=dp)                                      :: beta, sigma
      64          260 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: Qdata
      65              :       TYPE(arnoldi_control_type), POINTER                :: control
      66              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
      67              : 
      68          260 :       CALL timeset(routineN, handle)
      69              : 
      70              :       ! This is just a terribly inefficient implementation but I hope it is correct and might serve as a reference
      71          260 :       ar_data => get_data(arnoldi_env)
      72          260 :       control => get_control(arnoldi_env)
      73          260 :       msize = control%current_step
      74          260 :       nwant = control%nval_out
      75         1560 :       ALLOCATE (tmp_mat(msize, msize)); ALLOCATE (safe_mat(msize, msize))
      76         1300 :       ALLOCATE (Q(msize, msize)); ALLOCATE (tmp_mat1(msize, msize))
      77          260 :       ALLOCATE (work_measure(1))
      78         1560 :       ALLOCATE (tau(msize)); ALLOCATE (Qdata(msize, msize))
      79              :       !make Q identity
      80       236484 :       Q = CMPLX(0.0, 0.0, dp)
      81         7108 :       DO i = 1, msize
      82         7108 :          Q(i, i) = CMPLX(1.0, 0.0, dp)
      83              :       END DO
      84              : 
      85              :       ! Looks a bit odd, but safe_mat will contain the result in the end, while tmpmat gets violated by lapack
      86       236484 :       tmp_mat(:, :) = CMPLX(ar_data%Hessenberg(1:msize, 1:msize), 0.0, KIND=dp)
      87       236484 :       safe_mat(:, :) = tmp_mat(:, :)
      88              : 
      89         7108 :       DO i = 1, msize
      90              :          ! A bit a strange check but in the end we only want to shift the unwanted evals
      91       222788 :          IF (ANY(control%selected_ind == i)) CYCLE
      92              :          ! Here we shift the matrix by subtracting unwanted evals from the diagonal
      93       222008 :          DO j = 1, msize
      94       222008 :             tmp_mat(j, j) = tmp_mat(j, j) - ar_data%evals(i)
      95              :          END DO
      96              :          ! Now we repair the damage by QR factorizing
      97         6328 :          lwork = -1
      98         6328 :          CALL zgeqrf(msize, msize, tmp_mat, msize, tau, work_measure, lwork, info)
      99         6328 :          lwork = INT(work_measure(1))
     100         6328 :          IF (ALLOCATED(work)) THEN
     101         6068 :             IF (SIZE(work) < lwork) THEN
     102            0 :                DEALLOCATE (work)
     103              :             END IF
     104              :          END IF
     105         6848 :          IF (.NOT. ALLOCATED(work)) ALLOCATE (work(lwork))
     106         6328 :          CALL zgeqrf(msize, msize, tmp_mat, msize, tau, work, lwork, info)
     107              :          ! Ask Lapack to reconstruct Q from its own way of storing data (tmpmat will contain Q)
     108         6328 :          CALL zungqr(msize, msize, msize, tmp_mat, msize, tau, work, lwork, info)
     109              :          ! update Q=Q*Q_current
     110      9429816 :          tmp_mat1(:, :) = Q(:, :)
     111              :          CALL zgemm('N', 'N', msize, msize, msize, CMPLX(1.0, 0.0, dp), tmp_mat1, &
     112         6328 :                     msize, tmp_mat, msize, CMPLX(0.0, 0.0, dp), Q, msize)
     113              :          ! Update H=(Q*)HQ
     114              :          CALL zgemm('C', 'N', msize, msize, msize, CMPLX(1.0, 0.0, dp), tmp_mat, &
     115         6328 :                     msize, safe_mat, msize, CMPLX(0.0, 0.0, dp), tmp_mat1, msize)
     116              :          CALL zgemm('N', 'N', msize, msize, msize, CMPLX(1.0, 0.0, dp), tmp_mat1, &
     117         6328 :                     msize, tmp_mat, msize, CMPLX(0.0, 0.0, dp), safe_mat, msize)
     118              : 
     119              :          ! this one is crucial for numerics not to accumulate noise in the subdiagonals
     120       222008 :          DO j = 1, msize
     121      4508720 :             safe_mat(j + 2:msize, j) = CMPLX(0.0, 0.0, dp)
     122              :          END DO
     123      9430596 :          tmp_mat(:, :) = safe_mat(:, :)
     124              :       END DO
     125              : 
     126              :       ! Now we can compute our restart quantities
     127       243332 :       ar_data%Hessenberg = 0.0_dp
     128       236484 :       ar_data%Hessenberg(1:msize, 1:msize) = REAL(safe_mat, KIND=dp)
     129       236484 :       Qdata(:, :) = REAL(Q(:, :), KIND=dp)
     130              : 
     131          260 :       beta = ar_data%Hessenberg(nwant + 1, nwant); sigma = Qdata(msize, nwant)
     132              : 
     133              :       !update the residuum and the basis vectors
     134          260 :       IF (control%local_comp) THEN
     135       506474 :          ar_data%f_vec = MATMUL(ar_data%local_history(:, 1:msize), Qdata(1:msize, nwant + 1))*beta + ar_data%f_vec(:)*sigma
     136      1449274 :          ar_data%local_history(:, 1:nwant) = MATMUL(ar_data%local_history(:, 1:msize), Qdata(1:msize, 1:nwant))
     137              :       END IF
     138              :       ! Set the current step to nwant so the subspace build knows where to start
     139          260 :       control%current_step = nwant
     140              : 
     141          260 :       DEALLOCATE (tmp_mat, safe_mat, Q, Qdata, tmp_mat1, work, tau, work_measure)
     142          260 :       CALL timestop(handle)
     143              : 
     144          260 :    END SUBROUTINE arnoldi_iram
     145              : 
     146              : ! **************************************************************************************************
     147              : !> \brief Call the correct eigensolver, in the arnoldi method only the right
     148              : !>        eigenvectors are used. Lefts are created here but dumped immediately
     149              : !>        This is only the serial version
     150              : !> \param arnoldi_env ...
     151              : ! **************************************************************************************************
     152       138267 :    SUBROUTINE compute_evals(arnoldi_env)
     153              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     154              : 
     155              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'compute_evals'
     156              : 
     157              :       COMPLEX(dp), ALLOCATABLE, DIMENSION(:, :)          :: levec
     158              :       INTEGER                                            :: handle, ndim
     159              :       TYPE(arnoldi_control_type), POINTER                :: control
     160              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     161              : 
     162       138267 :       CALL timeset(routineN, handle)
     163              : 
     164       138267 :       ar_data => get_data(arnoldi_env)
     165       138267 :       control => get_control(arnoldi_env)
     166       138267 :       ndim = control%current_step
     167       553068 :       ALLOCATE (levec(ndim, ndim))
     168              : 
     169              :       ! Needs antoher interface as the calls to real and complex geev differ (sucks!)
     170              :       ! only perform the diagonalization on processors which hold data
     171       138267 :       IF (control%generalized_ev) THEN
     172              :          CALL arnoldi_symm_local_diag('V', ar_data%Hessenberg(1:ndim, 1:ndim), ndim, &
     173         4623 :                                       ar_data%evals(1:ndim), ar_data%revec(1:ndim, 1:ndim))
     174              :       ELSE
     175       133644 :          IF (control%symmetric) THEN
     176              :             CALL arnoldi_tridiag_local_diag('N', 'V', ar_data%Hessenberg(1:ndim, 1:ndim), ndim, &
     177         8769 :                                             ar_data%evals(1:ndim), ar_data%revec(1:ndim, 1:ndim), levec)
     178              :          ELSE
     179              :             CALL arnoldi_general_local_diag('N', 'V', ar_data%Hessenberg(1:ndim, 1:ndim), ndim, &
     180       124875 :                                             ar_data%evals(1:ndim), ar_data%revec(1:ndim, 1:ndim), levec)
     181              :          END IF
     182              :       END IF
     183              : 
     184       138267 :       DEALLOCATE (levec)
     185       138267 :       CALL timestop(handle)
     186              : 
     187       138267 :    END SUBROUTINE compute_evals
     188              : 
     189              : ! **************************************************************************************************
     190              : !> \brief Interface for the initialization of the arnoldi subspace creation
     191              : !>        currently it can only setup a random vector but can be improved to
     192              : !>        various types of restarts easily
     193              : !> \param matrix pointer to the matrices as described in main interface
     194              : !> \param vectors work vectors for the matrix vector multiplications
     195              : !> \param arnoldi_env all data concerning the subspace
     196              : ! **************************************************************************************************
     197       133384 :    SUBROUTINE arnoldi_init(matrix, vectors, arnoldi_env)
     198              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: matrix
     199              :       TYPE(m_x_v_vectors_type)                           :: vectors
     200              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     201              : 
     202              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'arnoldi_init'
     203              : 
     204              :       INTEGER                                            :: col, col_size, handle, i, iseed(4), &
     205              :                                                             ncol_local, nrow_local, row, row_size
     206              :       LOGICAL                                            :: local_comp
     207              :       REAL(dp)                                           :: rnorm
     208              :       REAL(kind=dp)                                      :: norm
     209              :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: v_vec, w_vec
     210       133384 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: data_block
     211              :       TYPE(arnoldi_control_type), POINTER                :: control
     212              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     213              :       TYPE(dbcsr_iterator_type)                          :: iter
     214              :       TYPE(mp_comm_type)                                 :: pcol_group
     215              : 
     216       133384 :       CALL timeset(routineN, handle)
     217              : 
     218       133384 :       control => get_control(arnoldi_env)
     219       133384 :       pcol_group = control%pcol_group
     220       133384 :       local_comp = control%local_comp
     221              : 
     222       133384 :       ar_data => get_data(arnoldi_env)
     223              : 
     224              :       ! create a local data copy to store the vectors and make Gram Schmidt a bit simpler
     225       133384 :       CALL dbcsr_get_info(matrix=vectors%input_vec, nfullrows_local=nrow_local, nfullcols_local=ncol_local)
     226       352549 :       ALLOCATE (v_vec(nrow_local))
     227       304946 :       ALLOCATE (w_vec(nrow_local))
     228      1772410 :       v_vec = 0.0_dp; w_vec = 0.0_dp
     229    144042064 :       ar_data%Hessenberg = 0.0_dp
     230              : 
     231       133384 :       IF (control%has_initial_vector) THEN
     232              :          ! after calling the set routine the initial vector is stored in f_vec
     233         2740 :          CALL transfer_local_array_to_dbcsr(vectors%input_vec, ar_data%f_vec, nrow_local, control%local_comp)
     234              :       ELSE
     235              :          ! Setup the initial normalized random vector (sufficient if it only happens on proc_col 0)
     236       130644 :          CALL dbcsr_iterator_start(iter, vectors%input_vec)
     237       239903 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     238       109259 :             CALL dbcsr_iterator_next_block(iter, row, col, data_block, row_size=row_size, col_size=col_size)
     239       109259 :             iseed(1) = 2; iseed(2) = MOD(row, 4095); iseed(3) = MOD(col, 4095); iseed(4) = 11
     240       239903 :             CALL dlarnv(2, iseed, row_size*col_size, data_block)
     241              :          END DO
     242       130644 :          CALL dbcsr_iterator_stop(iter)
     243              :       END IF
     244              : 
     245       133384 :       CALL transfer_dbcsr_to_local_array(vectors%input_vec, v_vec, nrow_local, control%local_comp)
     246              : 
     247              :       ! compute the vector norm of the random vectorm, get it real valued as well (rnorm)
     248       133384 :       CALL compute_norms(v_vec, norm, rnorm, control%pcol_group)
     249              : 
     250       133384 :       IF (rnorm == 0) rnorm = 1 ! catch case where this rank has no actual data
     251       133384 :       CALL dbcsr_scale(vectors%input_vec, REAL(1.0, dp)/rnorm)
     252              : 
     253              :       ! Everything prepared, initialize the Arnoldi iteration
     254       133384 :       CALL transfer_dbcsr_to_local_array(vectors%input_vec, v_vec, nrow_local, control%local_comp)
     255              : 
     256              :       ! This permits to compute the subspace of a matrix which is a product of multiple matrices
     257       266768 :       DO i = 1, SIZE(matrix)
     258              :          CALL dbcsr_matrix_colvec_multiply(matrix(i)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     259       133384 :                                            0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     260       266768 :          CALL dbcsr_copy(vectors%input_vec, vectors%result_vec)
     261              :       END DO
     262              : 
     263       133384 :       CALL transfer_dbcsr_to_local_array(vectors%result_vec, w_vec, nrow_local, control%local_comp)
     264              : 
     265              :       ! Put the projection into the Hessenberg matrix, and make the vectors orthonormal
     266       886205 :       ar_data%Hessenberg(1, 1) = DOT_PRODUCT(v_vec, w_vec)
     267       133384 :       CALL pcol_group%sum(ar_data%Hessenberg(1, 1))
     268       886205 :       ar_data%f_vec = w_vec - v_vec*ar_data%Hessenberg(1, 1)
     269              : 
     270       886205 :       ar_data%local_history(:, 1) = v_vec(:)
     271              : 
     272              :       ! We did the first step in here so we should set the current step for the subspace generation accordingly
     273       133384 :       control%current_step = 1
     274              : 
     275       133384 :       DEALLOCATE (v_vec, w_vec)
     276       133384 :       CALL timestop(handle)
     277              : 
     278       266768 :    END SUBROUTINE arnoldi_init
     279              : 
     280              : ! **************************************************************************************************
     281              : !> \brief Computes the initial guess for the solution of the generalized eigenvalue
     282              : !>        using the arnoldi method
     283              : !> \param matrix pointer to the matrices as described in main interface
     284              : !> \param matrix_arnoldi ...
     285              : !> \param vectors work vectors for the matrix vector multiplications
     286              : !> \param arnoldi_env all data concerning the subspace
     287              : ! **************************************************************************************************
     288         3747 :    SUBROUTINE gev_arnoldi_init(matrix, matrix_arnoldi, vectors, arnoldi_env)
     289              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: matrix, matrix_arnoldi
     290              :       TYPE(m_x_v_vectors_type)                           :: vectors
     291              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     292              : 
     293              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'gev_arnoldi_init'
     294              : 
     295              :       INTEGER                                            :: col, col_size, handle, iseed(4), &
     296              :                                                             ncol_local, nrow_local, row, row_size
     297              :       LOGICAL                                            :: local_comp
     298              :       REAL(dp)                                           :: rnorm
     299              :       REAL(kind=dp)                                      :: denom, norm
     300              :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: v_vec, w_vec
     301         3747 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: data_block
     302              :       TYPE(arnoldi_control_type), POINTER                :: control
     303              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     304              :       TYPE(dbcsr_iterator_type)                          :: iter
     305              :       TYPE(mp_comm_type)                                 :: pcol_group
     306              : 
     307         3747 :       CALL timeset(routineN, handle)
     308              : 
     309         3747 :       control => get_control(arnoldi_env)
     310         3747 :       pcol_group = control%pcol_group
     311         3747 :       local_comp = control%local_comp
     312              : 
     313         3747 :       ar_data => get_data(arnoldi_env)
     314              : 
     315              :       ! create a local data copy to store the vectors and make Gram Schmidt a bit simpler
     316         3747 :       CALL dbcsr_get_info(matrix=vectors%input_vec, nfullrows_local=nrow_local, nfullcols_local=ncol_local)
     317        11213 :       ALLOCATE (v_vec(nrow_local))
     318         7466 :       ALLOCATE (w_vec(nrow_local))
     319       131846 :       v_vec = 0.0_dp; w_vec = 0.0_dp
     320      1652427 :       ar_data%Hessenberg = 0.0_dp
     321              : 
     322         3747 :       IF (control%has_initial_vector) THEN
     323              :          ! after calling the set routine the initial vector is stored in f_vec
     324         1992 :          CALL transfer_local_array_to_dbcsr(vectors%input_vec, ar_data%f_vec, nrow_local, control%local_comp)
     325              :       ELSE
     326              :          ! Setup the initial normalized random vector (sufficient if it only happens on proc_col 0)
     327         1755 :          CALL dbcsr_iterator_start(iter, vectors%input_vec)
     328         5266 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     329         3511 :             CALL dbcsr_iterator_next_block(iter, row, col, data_block, row_size=row_size, col_size=col_size)
     330         3511 :             iseed(1) = 2; iseed(2) = MOD(row, 4095); iseed(3) = MOD(col, 4095); iseed(4) = 11
     331         5266 :             CALL dlarnv(2, iseed, row_size*col_size, data_block)
     332              :          END DO
     333         1755 :          CALL dbcsr_iterator_stop(iter)
     334              :       END IF
     335              : 
     336         3747 :       CALL transfer_dbcsr_to_local_array(vectors%input_vec, v_vec, nrow_local, control%local_comp)
     337              : 
     338              :       ! compute the vector norm of the reandom vectorm, get it real valued as well (rnorm)
     339         3747 :       CALL compute_norms(v_vec, norm, rnorm, control%pcol_group)
     340              : 
     341         3747 :       IF (rnorm == 0) rnorm = 1 ! catch case where this rank has no actual data
     342         3747 :       CALL dbcsr_scale(vectors%input_vec, REAL(1.0, dp)/rnorm)
     343              : 
     344              :       CALL dbcsr_matrix_colvec_multiply(matrix(1)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     345         3747 :                                         0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     346              : 
     347         3747 :       CALL transfer_dbcsr_to_local_array(vectors%result_vec, w_vec, nrow_local, control%local_comp)
     348              : 
     349              :       ar_data%rho_scale = 0.0_dp
     350        65923 :       ar_data%rho_scale = DOT_PRODUCT(v_vec, w_vec)
     351         3747 :       CALL pcol_group%sum(ar_data%rho_scale)
     352              : 
     353              :       CALL dbcsr_matrix_colvec_multiply(matrix(2)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     354         3747 :                                         0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     355              : 
     356         3747 :       CALL transfer_dbcsr_to_local_array(vectors%result_vec, w_vec, nrow_local, control%local_comp)
     357              : 
     358              :       denom = 0.0_dp
     359        65923 :       denom = DOT_PRODUCT(v_vec, w_vec)
     360         3747 :       CALL pcol_group%sum(denom)
     361         3747 :       IF (control%myproc == 0) ar_data%rho_scale = ar_data%rho_scale/denom
     362         3747 :       CALL control%mp_group%bcast(ar_data%rho_scale, 0)
     363              : 
     364              :       ! if the maximum ev is requested we need to optimize with -A-rho*B
     365         3747 :       CALL dbcsr_copy(matrix_arnoldi(1)%matrix, matrix(1)%matrix)
     366         3747 :       CALL dbcsr_add(matrix_arnoldi(1)%matrix, matrix(2)%matrix, 1.0_dp, -ar_data%rho_scale)
     367              : 
     368        65923 :       ar_data%x_vec = v_vec
     369              : 
     370         3747 :       CALL timestop(handle)
     371              : 
     372        11241 :    END SUBROUTINE gev_arnoldi_init
     373              : 
     374              : ! **************************************************************************************************
     375              : !> \brief Here we create the Krylov subspace and fill the Hessenberg matrix
     376              : !>        convergence check is only performed on subspace convergence
     377              : !>        Gram Schidt is used to orthonogonalize.
     378              : !>        If this is numericall not sufficient a Daniel, Gragg, Kaufman and Steward
     379              : !>        correction is performed
     380              : !> \param matrix ...
     381              : !> \param vectors ...
     382              : !> \param arnoldi_env ...
     383              : ! **************************************************************************************************
     384       133644 :    SUBROUTINE build_subspace(matrix, vectors, arnoldi_env)
     385              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: matrix
     386              :       TYPE(m_x_v_vectors_type), TARGET                   :: vectors
     387              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     388              : 
     389              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'build_subspace'
     390              : 
     391              :       INTEGER                                            :: handle, i, j, ncol_local, nrow_local
     392              :       REAL(dp)                                           :: rnorm
     393              :       REAL(kind=dp)                                      :: norm
     394              :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: h_vec, s_vec, v_vec, w_vec
     395              :       TYPE(arnoldi_control_type), POINTER                :: control
     396              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     397              :       TYPE(dbcsr_type), POINTER                          :: input_vec, result_vec, swap_vec
     398              : 
     399       133644 :       CALL timeset(routineN, handle)
     400              : 
     401       133644 :       ar_data => get_data(arnoldi_env)
     402       133644 :       control => get_control(arnoldi_env)
     403       133644 :       control%converged = .FALSE.
     404              : 
     405              :       ! create the vectors required during the iterations
     406       133644 :       CALL dbcsr_get_info(matrix=vectors%input_vec, nfullrows_local=nrow_local, nfullcols_local=ncol_local)
     407       525411 :       ALLOCATE (v_vec(nrow_local)); ALLOCATE (w_vec(nrow_local))
     408      1807744 :       v_vec = 0.0_dp; w_vec = 0.0_dp
     409       668220 :       ALLOCATE (s_vec(control%max_iter)); ALLOCATE (h_vec(control%max_iter))
     410              : 
     411       636284 :       DO j = control%current_step, control%max_iter - 1
     412              : 
     413              :          ! compute the vector norm of the residuum, get it real valued as well (rnorm)
     414       633064 :          CALL compute_norms(ar_data%f_vec, norm, rnorm, control%pcol_group)
     415              : 
     416              :          ! check convergence and inform everybody about it, a bit annoying to talk to everybody because of that
     417       633064 :          IF (control%myproc == 0) control%converged = rnorm < REAL(control%threshold, dp)
     418       633064 :          CALL control%mp_group%bcast(control%converged, 0)
     419       633064 :          IF (control%converged) EXIT
     420              : 
     421              :          ! transfer normalized residdum to history and its norm to the Hessenberg matrix
     422       502640 :          IF (rnorm == 0) rnorm = 1 ! catch case where this rank has no actual data
     423     14019314 :          v_vec(:) = ar_data%f_vec(:)/rnorm; ar_data%local_history(:, j + 1) = v_vec(:); ar_data%Hessenberg(j + 1, j) = norm
     424              : 
     425       502640 :          input_vec => vectors%input_vec
     426       502640 :          result_vec => vectors%result_vec
     427       502640 :          CALL transfer_local_array_to_dbcsr(input_vec, v_vec, nrow_local, control%local_comp)
     428              : 
     429              :          ! This permits to compute the subspace of a matrix which is a product of two matrices
     430      1005280 :          DO i = 1, SIZE(matrix)
     431              :             CALL dbcsr_matrix_colvec_multiply(matrix(i)%matrix, input_vec, result_vec, 1.0_dp, &
     432       502640 :                                               0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     433       502640 :             swap_vec => input_vec
     434       502640 :             input_vec => result_vec
     435      1005280 :             result_vec => swap_vec
     436              :          END DO
     437              : 
     438       502640 :          CALL transfer_dbcsr_to_local_array(input_vec, w_vec, nrow_local, control%local_comp)
     439              : 
     440              :          ! Let's do the orthonormalization, to get the new f_vec. First try the Gram Schmidt scheme
     441              :          CALL Gram_Schmidt_ortho(h_vec, ar_data%f_vec, s_vec, w_vec, nrow_local, j + 1, &
     442       502640 :                                  ar_data%local_history, ar_data%local_history, control%local_comp, control%pcol_group)
     443              : 
     444              :          ! A bit more expensive but simply always top up with a DGKS correction, otherwise numerics
     445              :          ! can become a problem later on, there is probably a good check whether it's necessary, but we don't perform it
     446              :          CALL DGKS_ortho(h_vec, ar_data%f_vec, s_vec, nrow_local, j + 1, ar_data%local_history, &
     447       502640 :                          ar_data%local_history, control%local_comp, control%pcol_group)
     448              :          ! Finally we can put the projections into our Hessenberg matrix
     449      4778459 :          ar_data%Hessenberg(1:j + 1, j + 1) = h_vec(1:j + 1)
     450       636284 :          control%current_step = j + 1
     451              :       END DO
     452              : 
     453              :       ! compute the vector norm of the final residuum and put it in to Hessenberg
     454       133644 :       CALL compute_norms(ar_data%f_vec, norm, rnorm, control%pcol_group)
     455       133644 :       ar_data%Hessenberg(control%current_step + 1, control%current_step) = norm
     456              : 
     457              :       ! broadcast the Hessenberg matrix so we don't need to care later on
     458    288437148 :       CALL control%mp_group%bcast(ar_data%Hessenberg, 0)
     459              : 
     460       133644 :       DEALLOCATE (v_vec, w_vec, h_vec, s_vec)
     461       133644 :       CALL timestop(handle)
     462              : 
     463       267288 :    END SUBROUTINE build_subspace
     464              : 
     465              : ! **************************************************************************************************
     466              : !> \brief builds the basis rothogonal wrt. the metric.
     467              : !>        The structure looks similar to normal arnoldi but norms, vectors and
     468              : !>        matrix_vector products are very differently defined. Therefore it is
     469              : !>        cleaner to put it in a separate subroutine to avoid confusion
     470              : !> \param matrix ...
     471              : !> \param vectors ...
     472              : !> \param arnoldi_env ...
     473              : ! **************************************************************************************************
     474         4623 :    SUBROUTINE gev_build_subspace(matrix, vectors, arnoldi_env)
     475              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: matrix
     476              :       TYPE(m_x_v_vectors_type)                           :: vectors
     477              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     478              : 
     479              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'gev_build_subspace'
     480              : 
     481              :       INTEGER                                            :: handle, j, ncol_local, nrow_local
     482              :       REAL(kind=dp)                                      :: norm
     483              :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: h_vec, s_vec, v_vec, w_vec
     484         4623 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: BZmat, CZmat, Zmat
     485              :       TYPE(arnoldi_control_type), POINTER                :: control
     486              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     487              :       TYPE(mp_comm_type)                                 :: pcol_group
     488              : 
     489         4623 :       CALL timeset(routineN, handle)
     490              : 
     491         4623 :       ar_data => get_data(arnoldi_env)
     492         4623 :       control => get_control(arnoldi_env)
     493         4623 :       control%converged = .FALSE.
     494         4623 :       pcol_group = control%pcol_group
     495              : 
     496              :       ! create the vectors required during the iterations
     497         4623 :       CALL dbcsr_get_info(matrix=vectors%input_vec, nfullrows_local=nrow_local, nfullcols_local=ncol_local)
     498        18434 :       ALLOCATE (v_vec(nrow_local)); ALLOCATE (w_vec(nrow_local))
     499       202241 :       v_vec = 0.0_dp; w_vec = 0.0_dp
     500        18492 :       ALLOCATE (s_vec(control%max_iter)); ALLOCATE (h_vec(control%max_iter))
     501        27680 :       ALLOCATE (Zmat(nrow_local, control%max_iter)); ALLOCATE (CZmat(nrow_local, control%max_iter))
     502        13840 :       ALLOCATE (BZmat(nrow_local, control%max_iter))
     503              : 
     504         4623 :       CALL transfer_local_array_to_dbcsr(vectors%input_vec, ar_data%x_vec, nrow_local, control%local_comp)
     505              :       CALL dbcsr_matrix_colvec_multiply(matrix(2)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     506         4623 :                                         0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     507         4623 :       CALL transfer_dbcsr_to_local_array(vectors%result_vec, BZmat(:, 1), nrow_local, control%local_comp)
     508              : 
     509              :       norm = 0.0_dp
     510       103432 :       norm = DOT_PRODUCT(ar_data%x_vec, BZmat(:, 1))
     511         4623 :       CALL pcol_group%sum(norm)
     512         4623 :       IF (control%local_comp) THEN
     513       202212 :          Zmat(:, 1) = ar_data%x_vec/SQRT(norm); BZmat(:, 1) = BZmat(:, 1)/SQRT(norm)
     514              :       END IF
     515              : 
     516        76933 :       DO j = 1, control%max_iter
     517        76933 :          control%current_step = j
     518        76933 :          CALL transfer_local_array_to_dbcsr(vectors%input_vec, Zmat(:, j), nrow_local, control%local_comp)
     519              :          CALL dbcsr_matrix_colvec_multiply(matrix(1)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     520        76933 :                                            0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     521        76933 :          CALL transfer_dbcsr_to_local_array(vectors%result_vec, CZmat(:, j), nrow_local, control%local_comp)
     522      1894388 :          w_vec(:) = CZmat(:, j)
     523              : 
     524              :          ! Let's do the orthonormalization, to get the new f_vec. First try the Gram Schmidt scheme
     525              :          CALL Gram_Schmidt_ortho(h_vec, ar_data%f_vec, s_vec, w_vec, nrow_local, j, &
     526        76933 :                                  BZmat, Zmat, control%local_comp, control%pcol_group)
     527              : 
     528              :          ! A bit more expensive but simpliy always top up with a DGKS correction, otherwise numerics
     529              :          ! can becom a problem later on, there is probably a good check, but we don't perform it
     530              :          CALL DGKS_ortho(h_vec, ar_data%f_vec, s_vec, nrow_local, j, BZmat, &
     531        76933 :                          Zmat, control%local_comp, control%pcol_group)
     532              : 
     533        76933 :          CALL transfer_local_array_to_dbcsr(vectors%input_vec, ar_data%f_vec, nrow_local, control%local_comp)
     534              :          CALL dbcsr_matrix_colvec_multiply(matrix(2)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     535        76933 :                                            0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     536        76933 :          CALL transfer_dbcsr_to_local_array(vectors%result_vec, v_vec, nrow_local, control%local_comp)
     537              :          norm = 0.0_dp
     538      1894388 :          norm = DOT_PRODUCT(ar_data%f_vec, v_vec)
     539        76933 :          CALL pcol_group%sum(norm)
     540              : 
     541        76933 :          IF (control%myproc == 0) control%converged = REAL(norm, dp) < EPSILON(REAL(1.0, dp))
     542        76933 :          CALL control%mp_group%bcast(control%converged, 0)
     543        76933 :          IF (control%converged) EXIT
     544        74809 :          IF (j == control%max_iter - 1) EXIT
     545              : 
     546        76933 :          IF (control%local_comp) THEN
     547      3509266 :             Zmat(:, j + 1) = ar_data%f_vec/SQRT(norm); BZmat(:, j + 1) = v_vec(:)/SQRT(norm)
     548              :          END IF
     549              :       END DO
     550              : 
     551              :       ! getting a bit more complicated here as the final matrix is again a product which has to be computed with the
     552              :       ! distributed vectors, therefore a sum along the first proc_col is necessary. As we want that matrix everywhere,
     553              :       ! we set it to zero before and compute the distributed product only on the first col and then sum over the full grid
     554      2038743 :       ar_data%Hessenberg = 0.0_dp
     555         4623 :       IF (control%local_comp) THEN
     556              :          ar_data%Hessenberg(1:control%current_step, 1:control%current_step) = &
     557     23250507 :             MATMUL(TRANSPOSE(CZmat(:, 1:control%current_step)), Zmat(:, 1:control%current_step))
     558              :       END IF
     559      4072863 :       CALL control%mp_group%sum(ar_data%Hessenberg)
     560              : 
     561      2073263 :       ar_data%local_history = Zmat
     562              :       ! broadcast the Hessenberg matrix so we don't need to care later on
     563              : 
     564         4623 :       DEALLOCATE (v_vec); DEALLOCATE (w_vec); DEALLOCATE (s_vec); DEALLOCATE (h_vec); DEALLOCATE (CZmat);
     565         4623 :       DEALLOCATE (Zmat); DEALLOCATE (BZmat)
     566              : 
     567         4623 :       CALL timestop(handle)
     568              : 
     569         9246 :    END SUBROUTINE gev_build_subspace
     570              : 
     571              : ! **************************************************************************************************
     572              : !> \brief Updates all data after an inner loop of the generalized ev arnoldi.
     573              : !>        Updates rho and C=A-rho*B accordingly.
     574              : !>        As an update scheme is used for he ev, the output ev has to be replaced
     575              : !>        with the updated one.
     576              : !>        Furthermore a convergence check is performed. The mv product could
     577              : !>        be skiiped by making clever use of the precomputed data, However,
     578              : !>        it is most likely not worth the effort.
     579              : !> \param matrix ...
     580              : !> \param matrix_arnoldi ...
     581              : !> \param vectors ...
     582              : !> \param arnoldi_env ...
     583              : ! **************************************************************************************************
     584         4623 :    SUBROUTINE gev_update_data(matrix, matrix_arnoldi, vectors, arnoldi_env)
     585              :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: matrix, matrix_arnoldi
     586              :       TYPE(m_x_v_vectors_type)                           :: vectors
     587              :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     588              : 
     589              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'gev_update_data'
     590              : 
     591              :       COMPLEX(dp)                                        :: val
     592              :       INTEGER                                            :: handle, i, ind, ncol_local, nrow_local
     593              :       REAL(dp)                                           :: rnorm
     594              :       REAL(kind=dp)                                      :: norm
     595         4623 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: v_vec
     596              :       TYPE(arnoldi_control_type), POINTER                :: control
     597              :       TYPE(arnoldi_data_type), POINTER                   :: ar_data
     598              : 
     599         4623 :       CALL timeset(routineN, handle)
     600              : 
     601         4623 :       control => get_control(arnoldi_env)
     602              : 
     603         4623 :       ar_data => get_data(arnoldi_env)
     604              : 
     605              :       ! compute the new shift, hack around the problem templating the conversion
     606         4623 :       val = ar_data%evals(control%selected_ind(1))
     607         4623 :       ar_data%rho_scale = ar_data%rho_scale + REAL(val, dp)
     608              :       ! compute the new eigenvector / initial guess for the next arnoldi loop
     609       103432 :       ar_data%x_vec = 0.0_dp
     610        81556 :       DO i = 1, control%current_step
     611        76933 :          val = ar_data%revec(i, control%selected_ind(1))
     612      1899011 :          ar_data%x_vec(:) = ar_data%x_vec(:) + ar_data%local_history(:, i)*REAL(val, dp)
     613              :       END DO
     614              :       ! ar_data%x_vec(:)=MATMUL(ar_data%local_history(:,1:control%current_step),&
     615              :       !                   ar_data%revec(1:control%current_step,control%selected_ind(1)))
     616              : 
     617              :       ! update the C-matrix (A-rho*B), if the maximum value is requested we have to use -A-rho*B
     618         4623 :       CALL dbcsr_copy(matrix_arnoldi(1)%matrix, matrix(1)%matrix)
     619         4623 :       CALL dbcsr_add(matrix_arnoldi(1)%matrix, matrix(2)%matrix, 1.0_dp, -ar_data%rho_scale)
     620              : 
     621              :       ! compute convergence and set the correct eigenvalue and eigenvector
     622         4623 :       CALL dbcsr_get_info(matrix=vectors%input_vec, nfullrows_local=nrow_local, nfullcols_local=ncol_local)
     623         4623 :       IF (ncol_local > 0) THEN
     624        13840 :          ALLOCATE (v_vec(nrow_local))
     625         4623 :          CALL compute_norms(ar_data%x_vec, norm, rnorm, control%pcol_group)
     626       103432 :          v_vec(:) = ar_data%x_vec(:)/rnorm
     627              :       END IF
     628         4623 :       CALL transfer_local_array_to_dbcsr(vectors%input_vec, v_vec, nrow_local, control%local_comp)
     629              :       CALL dbcsr_matrix_colvec_multiply(matrix_arnoldi(1)%matrix, vectors%input_vec, vectors%result_vec, 1.0_dp, &
     630         4623 :                                         0.0_dp, vectors%rep_row_vec, vectors%rep_col_vec)
     631         4623 :       CALL transfer_dbcsr_to_local_array(vectors%result_vec, v_vec, nrow_local, control%local_comp)
     632         4623 :       IF (ncol_local > 0) THEN
     633         4623 :          CALL compute_norms(v_vec, norm, rnorm, control%pcol_group)
     634              :          ! check convergence
     635         4623 :          control%converged = rnorm < control%threshold
     636         4623 :          DEALLOCATE (v_vec)
     637              :       END IF
     638              :       ! and broadcast the real eigenvalue
     639         4623 :       CALL control%mp_group%bcast(control%converged, 0)
     640         4623 :       ind = control%selected_ind(1)
     641         4623 :       CALL control%mp_group%bcast(ar_data%rho_scale, 0)
     642              : 
     643              :       ! Again the maximum value request is done on -A therefore the eigenvalue needs the opposite sign
     644         4623 :       ar_data%evals(ind) = ar_data%rho_scale
     645              : 
     646         4623 :       CALL timestop(handle)
     647              : 
     648         4623 :    END SUBROUTINE gev_update_data
     649              : 
     650              : ! **************************************************************************************************
     651              : !> \brief Helper routine to transfer the all data of a dbcsr matrix to a local array
     652              : !> \param vec ...
     653              : !> \param array ...
     654              : !> \param n ...
     655              : !> \param is_local ...
     656              : ! **************************************************************************************************
     657      1077145 :    SUBROUTINE transfer_dbcsr_to_local_array(vec, array, n, is_local)
     658              :       TYPE(dbcsr_type)                                   :: vec
     659              :       REAL(kind=dp), DIMENSION(:)                        :: array
     660              :       INTEGER                                            :: n
     661              :       LOGICAL                                            :: is_local
     662              : 
     663      1077145 :       REAL(kind=dp), DIMENSION(:), POINTER               :: data_vec
     664              : 
     665      2154290 :       data_vec => dbcsr_get_data_p(vec)
     666     14113001 :       IF (is_local) array(1:n) = data_vec(1:n)
     667              : 
     668      1077145 :    END SUBROUTINE transfer_dbcsr_to_local_array
     669              : 
     670              : ! **************************************************************************************************
     671              : !> \brief The inverse routine transferring data back from an array to a dbcsr
     672              : !> \param vec ...
     673              : !> \param array ...
     674              : !> \param n ...
     675              : !> \param is_local ...
     676              : ! **************************************************************************************************
     677       670484 :    SUBROUTINE transfer_local_array_to_dbcsr(vec, array, n, is_local)
     678              :       TYPE(dbcsr_type)                                   :: vec
     679              :       REAL(kind=dp), DIMENSION(:)                        :: array
     680              :       INTEGER                                            :: n
     681              :       LOGICAL                                            :: is_local
     682              : 
     683       670484 :       REAL(kind=dp), DIMENSION(:), POINTER               :: data_vec
     684              : 
     685      1340968 :       data_vec => dbcsr_get_data_p(vec)
     686     11337386 :       IF (is_local) data_vec(1:n) = array(1:n)
     687              : 
     688       670484 :    END SUBROUTINE transfer_local_array_to_dbcsr
     689              : 
     690              : ! **************************************************************************************************
     691              : !> \brief Gram-Schmidt in matrix vector form
     692              : !> \param h_vec ...
     693              : !> \param f_vec ...
     694              : !> \param s_vec ...
     695              : !> \param w_vec ...
     696              : !> \param nrow_local ...
     697              : !> \param j ...
     698              : !> \param local_history ...
     699              : !> \param reorth_mat ...
     700              : !> \param local_comp ...
     701              : !> \param pcol_group ...
     702              : ! **************************************************************************************************
     703       579573 :    SUBROUTINE Gram_Schmidt_ortho(h_vec, f_vec, s_vec, w_vec, nrow_local, &
     704       579573 :                                  j, local_history, reorth_mat, local_comp, pcol_group)
     705              :       REAL(kind=dp), DIMENSION(:)                        :: h_vec, f_vec, s_vec, w_vec
     706              :       INTEGER                                            :: nrow_local, j
     707              :       REAL(kind=dp), DIMENSION(:, :)                     :: local_history, reorth_mat
     708              :       LOGICAL                                            :: local_comp
     709              :       TYPE(mp_comm_type), INTENT(IN)                     :: pcol_group
     710              : 
     711              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'Gram_Schmidt_ortho'
     712              : 
     713              :       INTEGER                                            :: handle
     714              : 
     715       579573 :       CALL timeset(routineN, handle)
     716              : 
     717              :       ! Let's do the orthonormalization, first try the Gram Schmidt scheme
     718     45735335 :       h_vec = 0.0_dp; f_vec = 0.0_dp; s_vec = 0.0_dp
     719       579573 :       IF (local_comp) CALL dgemv('T', nrow_local, j, 1.0_dp, local_history, &
     720       484309 :                                  nrow_local, w_vec, 1, 0.0_dp, h_vec, 1)
     721     10560175 :       CALL pcol_group%sum(h_vec(1:j))
     722              : 
     723       579573 :       IF (local_comp) CALL dgemv('N', nrow_local, j, 1.0_dp, reorth_mat, &
     724       484309 :                                  nrow_local, h_vec, 1, 0.0_dp, f_vec, 1)
     725      9155365 :       f_vec(:) = w_vec(:) - f_vec(:)
     726              : 
     727       579573 :       CALL timestop(handle)
     728              : 
     729       579573 :    END SUBROUTINE Gram_Schmidt_ortho
     730              : 
     731              : ! **************************************************************************************************
     732              : !> \brief Compute the  Daniel, Gragg, Kaufman and Steward correction
     733              : !> \param h_vec ...
     734              : !> \param f_vec ...
     735              : !> \param s_vec ...
     736              : !> \param nrow_local ...
     737              : !> \param j ...
     738              : !> \param local_history ...
     739              : !> \param reorth_mat ...
     740              : !> \param local_comp ...
     741              : !> \param pcol_group ...
     742              : ! **************************************************************************************************
     743       579573 :    SUBROUTINE DGKS_ortho(h_vec, f_vec, s_vec, nrow_local, j, &
     744      1159146 :                          local_history, reorth_mat, local_comp, pcol_group)
     745              :       REAL(kind=dp), DIMENSION(:)                        :: h_vec, f_vec, s_vec
     746              :       INTEGER                                            :: nrow_local, j
     747              :       REAL(kind=dp), DIMENSION(:, :)                     :: local_history, reorth_mat
     748              :       LOGICAL                                            :: local_comp
     749              :       TYPE(mp_comm_type), INTENT(IN)                     :: pcol_group
     750              : 
     751              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'DGKS_ortho'
     752              : 
     753              :       INTEGER                                            :: handle
     754              : 
     755       579573 :       CALL timeset(routineN, handle)
     756              : 
     757       579573 :       IF (local_comp) CALL dgemv('T', nrow_local, j, 1.0_dp, local_history, &
     758       484309 :                                  nrow_local, f_vec, 1, 0.0_dp, s_vec, 1)
     759     10560175 :       CALL pcol_group%sum(s_vec(1:j))
     760       579573 :       IF (local_comp) CALL dgemv('N', nrow_local, j, -1.0_dp, reorth_mat, &
     761       484309 :                                  nrow_local, s_vec, 1, 1.0_dp, f_vec, 1)
     762      5569874 :       h_vec(1:j) = h_vec(1:j) + s_vec(1:j)
     763              : 
     764       579573 :       CALL timestop(handle)
     765              : 
     766       579573 :    END SUBROUTINE DGKS_ortho
     767              : 
     768              : ! **************************************************************************************************
     769              : !> \brief Compute the norm of a vector distributed along proc_col
     770              : !>        as local arrays. Always return the real part next to the complex rep.
     771              : !> \param vec ...
     772              : !> \param norm ...
     773              : !> \param rnorm ...
     774              : !> \param pcol_group ...
     775              : ! **************************************************************************************************
     776       913085 :    SUBROUTINE compute_norms(vec, norm, rnorm, pcol_group)
     777              :       REAL(kind=dp), DIMENSION(:)                        :: vec
     778              :       REAL(kind=dp)                                      :: norm
     779              :       REAL(dp)                                           :: rnorm
     780              :       TYPE(mp_comm_type), INTENT(IN)                     :: pcol_group
     781              : 
     782              :       ! the norm is computed along the processor column
     783     10095321 :       norm = DOT_PRODUCT(vec, vec)
     784       913085 :       CALL pcol_group%sum(norm)
     785       913085 :       rnorm = SQRT(REAL(norm, dp))
     786       913085 :       norm = rnorm
     787              : 
     788       913085 :    END SUBROUTINE compute_norms
     789              : 
     790          260 : END MODULE arnoldi_methods
        

Generated by: LCOV version 2.0-1