LCOV - code coverage report
Current view: top level - src/fm - cp_cfm_diag.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:cccd2f3) Lines: 85.6 % 195 167
Test Date: 2026-05-06 07:07:47 Functions: 100.0 % 6 6

            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 used for collecting diagonalization schemes available for cp_cfm_type
      10              : !> \note
      11              : !>      first version : only one routine right now
      12              : !> \author Joost VandeVondele (2003-09)
      13              : ! **************************************************************************************************
      14              : MODULE cp_cfm_diag
      15              :    USE cp_blacs_env, ONLY: cp_blacs_env_type
      16              :    USE cp_cfm_cholesky, ONLY: cp_cfm_cholesky_decompose
      17              :    USE cp_cfm_basic_linalg, ONLY: cp_cfm_gemm, &
      18              :                                   cp_cfm_column_scale, &
      19              :                                   cp_cfm_scale, &
      20              :                                   cp_cfm_triangular_invert, &
      21              :                                   cp_cfm_triangular_multiply
      22              :    USE cp_cfm_types, ONLY: cp_cfm_create, &
      23              :                            cp_cfm_get_info, &
      24              :                            cp_cfm_release, &
      25              :                            cp_cfm_set_element, &
      26              :                            cp_cfm_to_cfm, &
      27              :                            cp_cfm_type
      28              :    USE cp_fm_diag, ONLY: diag_check_requested, &
      29              :                          diag_check_warning_threshold, &
      30              :                          diag_type, &
      31              :                          direct_generalized_diagonalization, &
      32              :                          cusolver_n_min, &
      33              :                          FM_DIAG_TYPE_CUSOLVER, &
      34              :                          FM_DIAG_TYPE_SCALAPACK
      35              :    USE cp_fm_cusolver_api, ONLY: cp_cfm_general_cusolver
      36              : #if defined(__DLAF)
      37              :    USE cp_cfm_dlaf_api, ONLY: cp_cfm_diag_gen_dlaf, &
      38              :                               cp_cfm_diag_dlaf
      39              :    USE cp_dlaf_utils_api, ONLY: cp_dlaf_initialize, cp_dlaf_create_grid
      40              :    USE cp_fm_diag, ONLY: dlaf_neigvec_min, FM_DIAG_TYPE_DLAF
      41              : #endif
      42              :    USE cp_log_handling, ONLY: cp_to_string
      43              :    USE kinds, ONLY: default_string_length, &
      44              :                     dp
      45              :    USE machine, ONLY: default_output_unit
      46              :    USE mathconstants, ONLY: z_one, &
      47              :                             z_zero
      48              : #if defined (__HAS_IEEE_EXCEPTIONS)
      49              :    USE ieee_exceptions, ONLY: ieee_get_halting_mode, &
      50              :                               ieee_set_halting_mode, &
      51              :                               IEEE_ALL
      52              : #endif
      53              : #include "../base/base_uses.f90"
      54              : 
      55              :    IMPLICIT NONE
      56              :    PRIVATE
      57              : 
      58              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_cfm_diag'
      59              : 
      60              :    PUBLIC :: cp_cfm_heevd, cp_cfm_geeig, cp_cfm_geeig_canon
      61              : 
      62              : CONTAINS
      63              : 
      64              : ! **************************************************************************************************
      65              : !> \brief Perform a diagonalisation of a complex matrix
      66              : !> \param matrix ...
      67              : !> \param eigenvectors ...
      68              : !> \param eigenvalues ...
      69              : !> \par History
      70              : !>      12.2024 Added DLA-Future support [Rocco Meli]
      71              : !> \author Joost VandeVondele
      72              : ! **************************************************************************************************
      73        47424 :    SUBROUTINE cp_cfm_heevd(matrix, eigenvectors, eigenvalues)
      74              : 
      75              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix, eigenvectors
      76              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: eigenvalues
      77              : 
      78              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_heevd'
      79              : 
      80              :       INTEGER                                            :: handle
      81              : 
      82        47424 :       CALL timeset(routineN, handle)
      83              : 
      84              : #if defined(__DLAF)
      85              :       IF (diag_type == FM_DIAG_TYPE_DLAF .AND. matrix%matrix_struct%nrow_global >= dlaf_neigvec_min) THEN
      86              :          ! Initialize DLA-Future on-demand; if already initialized, does nothing
      87              :          CALL cp_dlaf_initialize()
      88              : 
      89              :          ! Create DLAF grid from BLACS context; if already present, does nothing
      90              :          CALL cp_dlaf_create_grid(matrix%matrix_struct%context%get_handle())
      91              : 
      92              :          CALL cp_cfm_diag_dlaf(matrix, eigenvectors, eigenvalues)
      93              :       ELSE
      94              : #endif
      95        47424 :          CALL cp_cfm_heevd_base(matrix, eigenvectors, eigenvalues)
      96              : #if defined(__DLAF)
      97              :       END IF
      98              : #endif
      99              : 
     100        47424 :       CALL timestop(handle)
     101              : 
     102        47424 :    END SUBROUTINE cp_cfm_heevd
     103              : 
     104              : ! **************************************************************************************************
     105              : !> \brief Perform a diagonalisation of a complex matrix
     106              : !> \param matrix ...
     107              : !> \param eigenvectors ...
     108              : !> \param eigenvalues ...
     109              : !> \par History
     110              : !>      - (De)Allocation checks updated (15.02.2011,MK)
     111              : !> \author Joost VandeVondele
     112              : ! **************************************************************************************************
     113        47424 :    SUBROUTINE cp_cfm_heevd_base(matrix, eigenvectors, eigenvalues)
     114              : 
     115              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix, eigenvectors
     116              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT) :: eigenvalues
     117              : 
     118              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_heevd_base'
     119              : 
     120        47424 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER  :: work
     121              :       COMPLEX(KIND=dp), DIMENSION(:, :), &
     122        47424 :          POINTER                               :: m
     123              :       INTEGER                                  :: handle, info, liwork, &
     124              :                                                   lrwork, lwork, n
     125        47424 :       INTEGER, DIMENSION(:), POINTER           :: iwork
     126        47424 :       REAL(KIND=dp), DIMENSION(:), POINTER     :: rwork
     127              : #if defined(__parallel)
     128              :       INTEGER, DIMENSION(9)                    :: descm, descv
     129              :       COMPLEX(KIND=dp), DIMENSION(:, :), &
     130        47424 :          POINTER                               :: v
     131              : #endif
     132              : #if defined (__HAS_IEEE_EXCEPTIONS)
     133              :       LOGICAL, DIMENSION(5)                    :: halt
     134              : #endif
     135              : 
     136        47424 :       CALL timeset(routineN, handle)
     137              : 
     138        47424 :       n = matrix%matrix_struct%nrow_global
     139        47424 :       m => matrix%local_data
     140        47424 :       ALLOCATE (iwork(1), rwork(1), work(1))
     141              :       ! work space query
     142        47424 :       lwork = -1
     143        47424 :       lrwork = -1
     144        47424 :       liwork = -1
     145              : 
     146              : #if defined(__parallel)
     147        47424 :       v => eigenvectors%local_data
     148       474240 :       descm(:) = matrix%matrix_struct%descriptor(:)
     149       474240 :       descv(:) = eigenvectors%matrix_struct%descriptor(:)
     150              :       CALL pzheevd('V', 'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
     151        47424 :                    work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     152              :       ! The work space query for lwork does not return always sufficiently large values.
     153              :       ! Let's add some margin to avoid crashes.
     154        47424 :       lwork = CEILING(REAL(work(1), KIND=dp)) + 1000
     155              :       ! needed to correct for a bug in scalapack, unclear how much the right number is
     156        47424 :       lrwork = CEILING(rwork(1)) + 1000000
     157        47424 :       liwork = iwork(1)
     158              : #else
     159              :       CALL zheevd('V', 'U', n, m(1, 1), SIZE(m, 1), eigenvalues(1), &
     160              :                   work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     161              :       lwork = CEILING(REAL(work(1), KIND=dp))
     162              :       lrwork = CEILING(rwork(1))
     163              :       liwork = iwork(1)
     164              : #endif
     165              : 
     166        47424 :       DEALLOCATE (iwork, rwork, work)
     167       331968 :       ALLOCATE (iwork(liwork), rwork(lrwork), work(lwork))
     168              : 
     169              : ! (Sca-)LAPACK takes advantage of IEEE754 exceptions for speedup.
     170              : ! Therefore, we disable floating point traps temporarily.
     171              : #if defined (__HAS_IEEE_EXCEPTIONS)
     172              :       CALL ieee_get_halting_mode(IEEE_ALL, halt)
     173              :       CALL ieee_set_halting_mode(IEEE_ALL, .FALSE.)
     174              : #endif
     175              : #if defined(__parallel)
     176              :       CALL pzheevd('V', 'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
     177        47424 :                    work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     178              : #else
     179              :       CALL zheevd('V', 'U', n, m(1, 1), SIZE(m, 1), eigenvalues(1), &
     180              :                   work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     181              :       eigenvectors%local_data = matrix%local_data
     182              : #endif
     183              : #if defined (__HAS_IEEE_EXCEPTIONS)
     184              :       CALL ieee_set_halting_mode(IEEE_ALL, halt)
     185              : #endif
     186              : 
     187        47424 :       DEALLOCATE (iwork, rwork, work)
     188        47424 :       IF (info /= 0) CPABORT("Diagonalisation of a complex matrix failed")
     189              : 
     190        47424 :       CALL timestop(handle)
     191              : 
     192        47424 :    END SUBROUTINE cp_cfm_heevd_base
     193              : 
     194              : ! **************************************************************************************************
     195              : !> \brief   Check C^H*S*C = I for a generalized complex eigenvalue problem.
     196              : !> \param overlap original overlap matrix S; used as work matrix and overwritten
     197              : !> \param eigenvectors eigenvectors C to be checked
     198              : !> \param scratch work matrix
     199              : !> \param nvec ...
     200              : ! **************************************************************************************************
     201           16 :    SUBROUTINE check_generalized_diag(overlap, eigenvectors, scratch, nvec)
     202              : 
     203              :       TYPE(cp_cfm_type), INTENT(IN)                      :: eigenvectors
     204              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: overlap, scratch
     205              :       INTEGER, INTENT(IN)                                :: nvec
     206              : 
     207              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'check_generalized_diag'
     208              : 
     209              :       CHARACTER(LEN=default_string_length)               :: diag_type_name
     210              :       COMPLEX(KIND=dp)                                   :: gold, test
     211              :       INTEGER                                            :: handle, i, j, ncol, nrow, output_unit
     212              :       REAL(KIND=dp)                                      :: eps, eps_abort, eps_warning
     213              : #if defined(__parallel)
     214              :       TYPE(cp_blacs_env_type), POINTER                   :: context
     215              :       INTEGER                                            :: il, jl, ipcol, iprow, &
     216              :                                                             mypcol, myprow, npcol, nprow
     217              :       INTEGER, DIMENSION(9)                              :: desca
     218              : #endif
     219              : 
     220           16 :       CALL timeset(routineN, handle)
     221              : 
     222           16 :       IF (.NOT. diag_check_requested()) THEN
     223            0 :          CALL timestop(handle)
     224            0 :          RETURN
     225              :       END IF
     226              : 
     227           16 :       output_unit = default_output_unit
     228           16 :       eps_warning = diag_check_warning_threshold()
     229           16 :       eps_abort = 10.0_dp*eps_warning
     230              : 
     231           16 :       nrow = eigenvectors%matrix_struct%nrow_global
     232           16 :       ncol = MIN(eigenvectors%matrix_struct%ncol_global, nvec)
     233              : 
     234           16 :       CALL cp_cfm_gemm("N", "N", nrow, ncol, nrow, z_one, overlap, eigenvectors, z_zero, scratch)
     235           16 :       CALL cp_cfm_gemm("C", "N", ncol, ncol, nrow, z_one, eigenvectors, scratch, z_zero, overlap)
     236              : 
     237           16 :       gold = z_zero
     238           16 :       test = z_zero
     239           16 :       eps = 0.0_dp
     240              : 
     241              : #if defined(__parallel)
     242           16 :       context => overlap%matrix_struct%context
     243           16 :       myprow = context%mepos(1)
     244           16 :       mypcol = context%mepos(2)
     245           16 :       nprow = context%num_pe(1)
     246           16 :       npcol = context%num_pe(2)
     247          160 :       desca(:) = overlap%matrix_struct%descriptor(:)
     248          160 :       outer: DO j = 1, ncol
     249         1456 :          DO i = 1, ncol
     250         1296 :             CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
     251         1440 :             IF ((iprow == myprow) .AND. (ipcol == mypcol)) THEN
     252          648 :                gold = MERGE(z_zero, z_one, i /= j)
     253          648 :                test = overlap%local_data(il, jl)
     254          648 :                eps = ABS(test - gold)
     255          648 :                IF (eps > eps_warning) EXIT outer
     256              :             END IF
     257              :          END DO
     258              :       END DO outer
     259              : #else
     260              :       outer: DO j = 1, ncol
     261              :          DO i = 1, ncol
     262              :             gold = MERGE(z_zero, z_one, i /= j)
     263              :             test = overlap%local_data(i, j)
     264              :             eps = ABS(test - gold)
     265              :             IF (eps > eps_warning) EXIT outer
     266              :          END DO
     267              :       END DO outer
     268              : #endif
     269              : 
     270           16 :       IF (eps > eps_warning) THEN
     271            0 :          IF (diag_type == FM_DIAG_TYPE_SCALAPACK) THEN
     272            0 :             diag_type_name = "HEGVX"
     273            0 :          ELSE IF (diag_type == FM_DIAG_TYPE_CUSOLVER) THEN
     274            0 :             diag_type_name = "CUSOLVER"
     275              : #if defined(__DLAF)
     276              :          ELSE IF (diag_type == FM_DIAG_TYPE_DLAF) THEN
     277              :             diag_type_name = "DLAF"
     278              : #endif
     279              :          ELSE
     280            0 :             diag_type_name = "generalized eigensolver"
     281              :          END IF
     282              :          WRITE (UNIT=output_unit, FMT="(/,T2,A,/,T2,A,I0,A,I0,A,ES10.3,/,T2,A,F0.0,A,ES10.3)") &
     283            0 :             "The generalized eigenvectors returned by "//TRIM(diag_type_name)//" are not S-orthonormal", &
     284            0 :             "Absolute deviation of matrix element (", i, ", ", j, ") is ", eps, &
     285            0 :             "The deviation from the expected value ", REAL(gold, KIND=dp), " is", eps
     286            0 :          IF (eps > eps_abort) THEN
     287            0 :             CPABORT("ERROR in "//routineN//": Check of generalized matrix diagonalization failed")
     288              :          ELSE
     289            0 :             CPWARN("Check of generalized matrix diagonalization failed in routine "//routineN)
     290              :          END IF
     291              :       END IF
     292              : 
     293           16 :       CALL timestop(handle)
     294              : 
     295              :    END SUBROUTINE check_generalized_diag
     296              : 
     297              : ! **************************************************************************************************
     298              : !> \brief General Eigenvalue Problem  AX = BXE
     299              : !>        Single option version: Cholesky decomposition of B
     300              : !> \param amatrix ...
     301              : !> \param bmatrix ...
     302              : !> \param eigenvectors ...
     303              : !> \param eigenvalues ...
     304              : !> \param work ...
     305              : !> \par History
     306              : !>      12.2024 Added DLA-Future support [Rocco Meli]
     307              : ! **************************************************************************************************
     308        33882 :    SUBROUTINE cp_cfm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
     309              : 
     310              :       TYPE(cp_cfm_type), INTENT(IN)                      :: amatrix, bmatrix, eigenvectors
     311              :       REAL(KIND=dp), DIMENSION(:)                        :: eigenvalues
     312              :       TYPE(cp_cfm_type), INTENT(IN)                      :: work
     313              : 
     314              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_geeig'
     315              : 
     316              :       INTEGER                                            :: handle, nao, nmo
     317              :       LOGICAL                                            :: check_eigenvectors
     318              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     319              :       TYPE(cp_cfm_type)                                  :: overlap_check, scratch_check
     320              : 
     321        33882 :       CALL timeset(routineN, handle)
     322              : 
     323        33882 :       CALL cp_cfm_get_info(amatrix, nrow_global=nao)
     324       101646 :       ALLOCATE (evals(nao))
     325        33882 :       nmo = SIZE(eigenvalues)
     326        33882 :       check_eigenvectors = diag_check_requested()
     327              : 
     328        33882 :       IF (diag_type == FM_DIAG_TYPE_CUSOLVER .AND. direct_generalized_diagonalization .AND. &
     329              :           nao >= cusolver_n_min) THEN
     330              :          ! Use cuSolverMP generalized eigenvalue solver without a CP2K-side
     331              :          ! Cholesky reduction.
     332            0 :          IF (check_eigenvectors) THEN
     333            0 :             CALL cp_cfm_create(overlap_check, bmatrix%matrix_struct)
     334            0 :             CALL cp_cfm_create(scratch_check, bmatrix%matrix_struct)
     335            0 :             CALL cp_cfm_to_cfm(bmatrix, overlap_check)
     336              :          END IF
     337            0 :          CALL cp_cfm_general_cusolver(amatrix, bmatrix, work, evals)
     338            0 :          IF (check_eigenvectors) THEN
     339            0 :             CALL check_generalized_diag(overlap_check, work, scratch_check, nmo)
     340            0 :             CALL cp_cfm_release(scratch_check)
     341            0 :             CALL cp_cfm_release(overlap_check)
     342              :          END IF
     343              : #if defined(__DLAF)
     344              :       ELSE IF (diag_type == FM_DIAG_TYPE_DLAF .AND. direct_generalized_diagonalization .AND. &
     345              :                nao >= dlaf_neigvec_min) THEN
     346              :          ! Initialize DLA-Future on-demand; if already initialized, does nothing
     347              :          CALL cp_dlaf_initialize()
     348              : 
     349              :          ! Create DLAF grid from BLACS context; if already present, does nothing
     350              :          CALL cp_dlaf_create_grid(amatrix%matrix_struct%context%get_handle())
     351              :          CALL cp_dlaf_create_grid(bmatrix%matrix_struct%context%get_handle())
     352              :          CALL cp_dlaf_create_grid(eigenvectors%matrix_struct%context%get_handle())
     353              : 
     354              :          ! Use DLA-Future generalized eigenvalue solver for large matrices
     355              :          IF (check_eigenvectors) THEN
     356              :             CALL cp_cfm_create(overlap_check, bmatrix%matrix_struct)
     357              :             CALL cp_cfm_create(scratch_check, bmatrix%matrix_struct)
     358              :             CALL cp_cfm_to_cfm(bmatrix, overlap_check)
     359              :          END IF
     360              :          CALL cp_cfm_diag_gen_dlaf(amatrix, bmatrix, work, evals)
     361              :          IF (check_eigenvectors) THEN
     362              :             CALL check_generalized_diag(overlap_check, work, scratch_check, nmo)
     363              :             CALL cp_cfm_release(scratch_check)
     364              :             CALL cp_cfm_release(overlap_check)
     365              :          END IF
     366              : #endif
     367              : #if defined(__parallel)
     368        33882 :       ELSE IF (diag_type == FM_DIAG_TYPE_SCALAPACK .AND. direct_generalized_diagonalization) THEN
     369              :          ! Use ScaLAPACK generalized eigenvalue solver without a CP2K-side
     370              :          ! Cholesky reduction.
     371           16 :          IF (check_eigenvectors) THEN
     372           16 :             CALL cp_cfm_create(overlap_check, bmatrix%matrix_struct)
     373           16 :             CALL cp_cfm_create(scratch_check, bmatrix%matrix_struct)
     374           16 :             CALL cp_cfm_to_cfm(bmatrix, overlap_check)
     375              :          END IF
     376           16 :          CALL cp_cfm_geeig_scalapack(amatrix, bmatrix, work, evals)
     377           16 :          IF (check_eigenvectors) THEN
     378           16 :             CALL check_generalized_diag(overlap_check, work, scratch_check, nmo)
     379           16 :             CALL cp_cfm_release(scratch_check)
     380           16 :             CALL cp_cfm_release(overlap_check)
     381              :          END IF
     382              : #endif
     383              :       ELSE
     384              :          ! Cholesky decompose S=U(T)U
     385        33866 :          CALL cp_cfm_cholesky_decompose(bmatrix)
     386              :          ! Invert to get U^(-1)
     387        33866 :          CALL cp_cfm_triangular_invert(bmatrix)
     388              :          ! Reduce to get U^(-T) * H * U^(-1)
     389        33866 :          CALL cp_cfm_triangular_multiply(bmatrix, amatrix, side="R")
     390        33866 :          CALL cp_cfm_triangular_multiply(bmatrix, amatrix, transa_tr="C")
     391              :          ! Diagonalize
     392        33866 :          CALL cp_cfm_heevd(matrix=amatrix, eigenvectors=work, eigenvalues=evals)
     393              :          ! Restore vectors C = U^(-1) * C*
     394        33866 :          CALL cp_cfm_triangular_multiply(bmatrix, work)
     395              :       END IF
     396              : 
     397        33882 :       CALL cp_cfm_to_cfm(work, eigenvectors, nmo)
     398       738612 :       eigenvalues(1:nmo) = evals(1:nmo)
     399              : 
     400        33882 :       DEALLOCATE (evals)
     401              : 
     402        33882 :       CALL timestop(handle)
     403              : 
     404        33882 :    END SUBROUTINE cp_cfm_geeig
     405              : 
     406              : ! **************************************************************************************************
     407              : !> \brief General Eigenvalue Problem AX = BXE using ScaLAPACK PZHEGVX.
     408              : !> \param amatrix ...
     409              : !> \param bmatrix ...
     410              : !> \param eigenvectors ...
     411              : !> \param eigenvalues ...
     412              : ! **************************************************************************************************
     413           16 :    SUBROUTINE cp_cfm_geeig_scalapack(amatrix, bmatrix, eigenvectors, eigenvalues)
     414              : 
     415              :       TYPE(cp_cfm_type), INTENT(IN)                      :: amatrix, bmatrix, eigenvectors
     416              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: eigenvalues
     417              : 
     418              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_geeig_scalapack'
     419              : 
     420              : #if defined(__parallel)
     421              :       REAL(KIND=dp), PARAMETER                           :: orfac = -1.0_dp, &
     422              :                                                             vl = 0.0_dp, &
     423              :                                                             vu = 0.0_dp
     424              : 
     425           16 :       COMPLEX(KIND=dp), DIMENSION(:), ALLOCATABLE        :: work
     426           16 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER         :: a, b, z
     427              :       INTEGER                                            :: handle, info, liwork, lwork, lrwork, &
     428              :                                                             m, n, nb, neig, npcol, nprow, nz
     429              :       INTEGER, DIMENSION(9)                              :: desca, descb, descz
     430           16 :       INTEGER, DIMENSION(:), ALLOCATABLE                 :: iclustr, ifail, iwork
     431              :       REAL(KIND=dp)                                      :: abstol
     432           16 :       REAL(KIND=dp), DIMENSION(:), ALLOCATABLE           :: gap, rwork, w
     433              : 
     434              :       INTEGER                                            :: mq0, nn, np0, npe
     435              :       INTEGER, EXTERNAL                                  :: iceil, numroc
     436              :       REAL(KIND=dp), EXTERNAL                            :: dlamch
     437              : #if defined (__HAS_IEEE_EXCEPTIONS)
     438              :       LOGICAL, DIMENSION(5)                              :: halt
     439              : #endif
     440              : #else
     441              :       INTEGER                                            :: handle
     442              : #endif
     443              : 
     444           16 :       CALL timeset(routineN, handle)
     445              : 
     446              : #if defined(__parallel)
     447           16 :       n = amatrix%matrix_struct%nrow_global
     448           16 :       neig = MIN(SIZE(eigenvalues), n)
     449              : 
     450           16 :       IF (neig == 0) THEN
     451            0 :          CALL timestop(handle)
     452            0 :          RETURN
     453              :       END IF
     454              : 
     455           16 :       IF (amatrix%matrix_struct%nrow_block /= amatrix%matrix_struct%ncol_block) THEN
     456            0 :          CPABORT("ERROR in "//routineN//": Invalid blocksize (no square blocks) found")
     457              :       END IF
     458              : 
     459           16 :       a => amatrix%local_data
     460           16 :       b => bmatrix%local_data
     461           16 :       z => eigenvectors%local_data
     462          160 :       desca(:) = amatrix%matrix_struct%descriptor(:)
     463          160 :       descb(:) = bmatrix%matrix_struct%descriptor(:)
     464          160 :       descz(:) = eigenvectors%matrix_struct%descriptor(:)
     465              : 
     466           16 :       nprow = amatrix%matrix_struct%context%num_pe(1)
     467           16 :       npcol = amatrix%matrix_struct%context%num_pe(2)
     468           16 :       npe = nprow*npcol
     469           16 :       nb = amatrix%matrix_struct%nrow_block
     470           16 :       nn = MAX(n, nb, 2)
     471           16 :       np0 = numroc(nn, nb, 0, 0, nprow)
     472           16 :       mq0 = MAX(numroc(nn, nb, 0, 0, npcol), nb)
     473              : 
     474           16 :       lwork = n + (np0 + mq0 + nb)*nb
     475           16 :       lrwork = 4*n + MAX(5*nn, np0*mq0) + iceil(neig, npe)*nn + MAX(0, neig - 1)*n
     476           16 :       liwork = 6*MAX(n, npe + 1, 4)
     477              : 
     478           48 :       ALLOCATE (gap(npe))
     479           48 :       gap = 0.0_dp
     480           48 :       ALLOCATE (iclustr(2*npe))
     481           80 :       iclustr = 0
     482           48 :       ALLOCATE (ifail(n))
     483          640 :       ifail = 0
     484           48 :       ALLOCATE (iwork(liwork))
     485           48 :       ALLOCATE (rwork(lrwork))
     486           48 :       ALLOCATE (w(n))
     487           48 :       ALLOCATE (work(lwork))
     488              : 
     489           16 :       abstol = 2.0_dp*dlamch("S")
     490              : 
     491              : #if defined (__HAS_IEEE_EXCEPTIONS)
     492              :       CALL ieee_get_halting_mode(IEEE_ALL, halt)
     493              :       CALL ieee_set_halting_mode(IEEE_ALL, .FALSE.)
     494              : #endif
     495              :       CALL pzhegvx(1, "V", "I", "U", n, a(1, 1), 1, 1, desca, b(1, 1), 1, 1, descb, &
     496              :                    vl, vu, 1, neig, abstol, m, nz, w(1), orfac, z(1, 1), 1, 1, descz, &
     497              :                    work(1), lwork, rwork(1), lrwork, iwork(1), liwork, ifail(1), &
     498           16 :                    iclustr(1), gap(1), info)
     499              : #if defined (__HAS_IEEE_EXCEPTIONS)
     500              :       CALL ieee_set_halting_mode(IEEE_ALL, halt)
     501              : #endif
     502              : 
     503           16 :       IF (info /= 0 .OR. m < neig .OR. nz < neig) THEN
     504            0 :          CPABORT("ERROR in PZHEGVX (ScaLAPACK), info="//TRIM(cp_to_string(info)))
     505              :       END IF
     506              : 
     507          640 :       eigenvalues(:) = 0.0_dp
     508          640 :       eigenvalues(1:neig) = w(1:neig)
     509              : 
     510           16 :       DEALLOCATE (gap, iclustr, ifail, iwork, rwork, w, work)
     511              : #else
     512              :       MARK_USED(amatrix)
     513              :       MARK_USED(bmatrix)
     514              :       MARK_USED(eigenvectors)
     515              :       MARK_USED(eigenvalues)
     516              :       CPABORT("ERROR in "//routineN//": PZHEGVX requested without ScaLAPACK support")
     517              : #endif
     518              : 
     519           16 :       CALL timestop(handle)
     520              : 
     521           16 :    END SUBROUTINE cp_cfm_geeig_scalapack
     522              : 
     523              : ! **************************************************************************************************
     524              : !> \brief General Eigenvalue Problem  AX = BXE
     525              : !>        Use canonical orthogonalization
     526              : !> \param amatrix ...
     527              : !> \param bmatrix ...
     528              : !> \param eigenvectors ...
     529              : !> \param eigenvalues ...
     530              : !> \param work ...
     531              : !> \param epseig ...
     532              : ! **************************************************************************************************
     533         2232 :    SUBROUTINE cp_cfm_geeig_canon(amatrix, bmatrix, eigenvectors, eigenvalues, work, epseig)
     534              : 
     535              :       TYPE(cp_cfm_type), INTENT(IN)                      :: amatrix, bmatrix, eigenvectors
     536              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: eigenvalues
     537              :       TYPE(cp_cfm_type), INTENT(IN)                      :: work
     538              :       REAL(KIND=dp), INTENT(IN)                          :: epseig
     539              : 
     540              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_geeig_canon'
     541              : 
     542              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: cevals
     543              :       INTEGER                                            :: handle, i, icol, irow, nao, nc, ncol, &
     544              :                                                             nmo, nx
     545              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     546              : 
     547         2232 :       CALL timeset(routineN, handle)
     548              : 
     549              :       ! Test sizes
     550         2232 :       CALL cp_cfm_get_info(amatrix, nrow_global=nao)
     551         2232 :       nmo = SIZE(eigenvalues)
     552        11160 :       ALLOCATE (evals(nao), cevals(nao))
     553              : 
     554              :       ! Diagonalize -S matrix, this way the NULL space is at the end of the spectrum
     555         2232 :       CALL cp_cfm_scale(-z_one, bmatrix)
     556         2232 :       CALL cp_cfm_heevd(bmatrix, work, evals)
     557        62970 :       evals(:) = -evals(:)
     558         2232 :       nc = nao
     559        62406 :       DO i = 1, nao
     560        62406 :          IF (evals(i) < epseig) THEN
     561           72 :             nc = i - 1
     562           72 :             EXIT
     563              :          END IF
     564              :       END DO
     565         2232 :       CPASSERT(nc /= 0)
     566              : 
     567         2232 :       IF (nc /= nao) THEN
     568           72 :          IF (nc < nmo) THEN
     569              :             ! Copy NULL space definition to last vectors of eigenvectors (if needed)
     570            0 :             ncol = nmo - nc
     571            0 :             CALL cp_cfm_to_cfm(work, eigenvectors, ncol, nc + 1, nc + 1)
     572              :          END IF
     573              :          ! Set NULL space in eigenvector matrix of S to zero
     574          636 :          DO icol = nc + 1, nao
     575        80028 :             DO irow = 1, nao
     576        79956 :                CALL cp_cfm_set_element(work, irow, icol, z_zero)
     577              :             END DO
     578              :          END DO
     579              :          ! Set small eigenvalues to a dummy save value
     580          636 :          evals(nc + 1:nao) = 1.0_dp
     581              :       END IF
     582              :       ! Calculate U*s**(-1/2)
     583        62970 :       cevals(:) = CMPLX(1.0_dp/SQRT(evals(:)), 0.0_dp, KIND=dp)
     584         2232 :       CALL cp_cfm_column_scale(work, cevals)
     585              :       ! Reduce to get U^(-C) * H * U^(-1)
     586         2232 :       CALL cp_cfm_gemm("C", "N", nao, nao, nao, z_one, work, amatrix, z_zero, bmatrix)
     587         2232 :       CALL cp_cfm_gemm("N", "N", nao, nao, nao, z_one, bmatrix, work, z_zero, amatrix)
     588         2232 :       IF (nc /= nao) THEN
     589              :          ! set diagonal values to save large value
     590          636 :          DO icol = nc + 1, nao
     591          636 :             CALL cp_cfm_set_element(amatrix, icol, icol, CMPLX(10000.0_dp, 0.0_dp, KIND=dp))
     592              :          END DO
     593              :       END IF
     594              :       ! Diagonalize
     595         2232 :       CALL cp_cfm_heevd(amatrix, bmatrix, evals)
     596        29248 :       eigenvalues(1:nmo) = evals(1:nmo)
     597         2232 :       nx = MIN(nc, nmo)
     598              :       ! Restore vectors C = U^(-1) * C*
     599         2232 :       CALL cp_cfm_gemm("N", "N", nao, nx, nc, z_one, work, bmatrix, z_zero, eigenvectors)
     600              : 
     601         2232 :       DEALLOCATE (evals)
     602              : 
     603         2232 :       CALL timestop(handle)
     604              : 
     605         4464 :    END SUBROUTINE cp_cfm_geeig_canon
     606              : 
     607              : END MODULE cp_cfm_diag
        

Generated by: LCOV version 2.0-1