LCOV - code coverage report
Current view: top level - src/arnoldi - arnoldi_geev.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 51 59 86.4 %
Date: 2025-01-30 06:53:08 Functions: 3 3 100.0 %

          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 provides a unified interface to lapack geev routines
      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_geev
      17             :    USE kinds,                           ONLY: dp
      18             : #include "../base/base_uses.f90"
      19             : 
      20             :    IMPLICIT NONE
      21             : 
      22             :    PRIVATE
      23             : 
      24             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'arnoldi_geev'
      25             : 
      26             :    PUBLIC :: arnoldi_general_local_diag, arnoldi_tridiag_local_diag, arnoldi_symm_local_diag
      27             : 
      28             : CONTAINS
      29             : 
      30             : ! **************************************************************************************************
      31             : !> \brief ...
      32             : !> \param jobvr ...
      33             : !> \param matrix ...
      34             : !> \param ndim ...
      35             : !> \param evals ...
      36             : !> \param revec ...
      37             : ! **************************************************************************************************
      38        4463 :    SUBROUTINE arnoldi_symm_local_diag(jobvr, matrix, ndim, evals, revec)
      39             :       CHARACTER(1)                                       :: jobvr
      40             :       REAL(dp), DIMENSION(:, :)                          :: matrix
      41             :       INTEGER                                            :: ndim
      42             :       COMPLEX(dp), DIMENSION(:)                          :: evals
      43             :       COMPLEX(dp), DIMENSION(:, :)                       :: revec
      44             : 
      45        8926 :       INTEGER                                            :: i, info, liwork, lwork, iwork(3 + 5*ndim)
      46        8926 :       REAL(dp)                                           :: tmp_array(ndim, ndim), &
      47        8926 :                                                             work(1 + 6*ndim + 2*ndim**2)
      48        8926 :       REAL(dp), DIMENSION(ndim)                          :: eval
      49             : 
      50        4463 :       lwork = 1 + 6*ndim + 2*ndim**2
      51        4463 :       liwork = 3 + 5*ndim
      52             : 
      53     1374755 :       tmp_array(:, :) = matrix(:, :)
      54        4463 :       CALL dsyevd(jobvr, "U", ndim, tmp_array, ndim, eval, work, lwork, iwork, liwork, info)
      55             : 
      56       78384 :       DO i = 1, ndim
      57     1370292 :          revec(:, i) = CMPLX(tmp_array(:, i), REAL(0.0, dp), dp)
      58       78384 :          evals(i) = CMPLX(eval(i), 0.0, dp)
      59             :       END DO
      60             : 
      61        4463 :    END SUBROUTINE arnoldi_symm_local_diag
      62             : 
      63             : ! **************************************************************************************************
      64             : !> \brief ...
      65             : !> \param jobvl ...
      66             : !> \param jobvr ...
      67             : !> \param matrix ...
      68             : !> \param ndim ...
      69             : !> \param evals ...
      70             : !> \param revec ...
      71             : !> \param levec ...
      72             : ! **************************************************************************************************
      73        8652 :    SUBROUTINE arnoldi_tridiag_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
      74             :       CHARACTER(1)                                       :: jobvl, jobvr
      75             :       REAL(dp), DIMENSION(:, :)                          :: matrix
      76             :       INTEGER                                            :: ndim
      77             :       COMPLEX(dp), DIMENSION(:)                          :: evals
      78             :       COMPLEX(dp), DIMENSION(:, :)                       :: revec, levec
      79             : 
      80             :       INTEGER                                            :: i, info
      81       17304 :       REAL(dp)                                           :: work(20*ndim)
      82       17304 :       REAL(dp), DIMENSION(ndim)                          :: diag, offdiag
      83       17304 :       REAL(dp), DIMENSION(ndim, ndim)                    :: evec_r
      84             : 
      85             :       MARK_USED(jobvl) !the argument has to be here for the template to work
      86             : 
      87        8652 :       levec(1, 1) = CMPLX(0.0, 0.0, dp)
      88        8652 :       info = 0
      89        8652 :       diag(ndim) = matrix(ndim, ndim)
      90       95377 :       DO i = 1, ndim - 1
      91       86725 :          diag(i) = matrix(i, i)
      92       95377 :          offdiag(i) = matrix(i + 1, i)
      93             : 
      94             :       END DO
      95             : 
      96        8652 :       CALL dstev(jobvr, ndim, diag, offdiag, evec_r, ndim, work, info)
      97             : 
      98      104029 :       DO i = 1, ndim
      99     2214198 :          revec(:, i) = CMPLX(evec_r(:, i), REAL(0.0, dp), dp)
     100      104029 :          evals(i) = CMPLX(diag(i), 0.0, dp)
     101             :       END DO
     102        8652 :    END SUBROUTINE arnoldi_tridiag_local_diag
     103             : 
     104             : ! **************************************************************************************************
     105             : !> \brief ...
     106             : !> \param jobvl ...
     107             : !> \param jobvr ...
     108             : !> \param matrix ...
     109             : !> \param ndim ...
     110             : !> \param evals ...
     111             : !> \param revec ...
     112             : !> \param levec ...
     113             : ! **************************************************************************************************
     114      116673 :    SUBROUTINE arnoldi_general_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
     115             :       CHARACTER(1)                                       :: jobvl, jobvr
     116             :       REAL(dp), DIMENSION(:, :)                          :: matrix
     117             :       INTEGER                                            :: ndim
     118             :       COMPLEX(dp), DIMENSION(:)                          :: evals
     119             :       COMPLEX(dp), DIMENSION(:, :)                       :: revec, levec
     120             : 
     121             :       INTEGER                                            :: i, info, lwork
     122      233346 :       LOGICAL                                            :: selects(ndim)
     123      233346 :       REAL(dp)                                           :: norm, tmp_array(ndim, ndim), &
     124      233346 :                                                             work(20*ndim)
     125      233346 :       REAL(dp), DIMENSION(ndim)                          :: eval1, eval2
     126      116673 :       REAL(dp), DIMENSION(ndim, ndim)                    :: evec_l, evec_r
     127             : 
     128             :       MARK_USED(jobvr) !the argument has to be here for the template to work
     129             :       MARK_USED(jobvl) !the argument has to be here for the template to work
     130             : 
     131     1115087 :       eval1 = REAL(0.0, dp); eval2 = REAL(0.0, dp)
     132     6134419 :       tmp_array(:, :) = matrix(:, :)
     133             :       ! ask lapack how much space it would like in the work vector, don't ask me why
     134      116673 :       lwork = -1
     135      116673 :       CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
     136             : 
     137      116673 :       lwork = MIN(20*ndim, INT(work(1)))
     138      116673 :       CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
     139      116673 :       CALL dtrevc('R', 'B', selects, ndim, tmp_array, ndim, evec_l, ndim, evec_r, ndim, ndim, ndim, work, info)
     140             : 
     141             :       ! compose the eigenvectors, lapacks way of storing them is a pain
     142             :       ! if eval is complex, then the complex conj pair of evec can be constructed from the i and i+1st evec
     143             :       ! Unfortunately dtrevc computes the ev such that the largest is set to one and not normalized
     144      116673 :       i = 1
     145      615880 :       DO WHILE (i .LE. ndim)
     146      615880 :          IF (ABS(eval2(i)) .LT. EPSILON(REAL(0.0, dp))) THEN
     147    11536285 :             evec_r(:, i) = evec_r(:, i)/SQRT(DOT_PRODUCT(evec_r(:, i), evec_r(:, i)))
     148     6017746 :             revec(:, i) = CMPLX(evec_r(:, i), REAL(0.0, dp), dp)
     149     6017746 :             levec(:, i) = CMPLX(evec_l(:, i), REAL(0.0, dp), dp)
     150      499207 :             i = i + 1
     151           0 :          ELSE IF (eval2(i) .GT. EPSILON(REAL(0.0, dp))) THEN
     152           0 :             norm = SQRT(SUM(evec_r(:, i)**2.0_dp) + SUM(evec_r(:, i + 1)**2.0_dp))
     153           0 :             revec(:, i) = CMPLX(evec_r(:, i), evec_r(:, i + 1), dp)/norm
     154           0 :             revec(:, i + 1) = CMPLX(evec_r(:, i), -evec_r(:, i + 1), dp)/norm
     155           0 :             levec(:, i) = CMPLX(evec_l(:, i), evec_l(:, i + 1), dp)
     156           0 :             levec(:, i + 1) = CMPLX(evec_l(:, i), -evec_l(:, i + 1), dp)
     157           0 :             i = i + 2
     158             :          ELSE
     159           0 :             CPABORT('something went wrong while sorting the EV in arnoldi_geev')
     160             :          END IF
     161             :       END DO
     162             : 
     163             :       ! this is to keep the interface consistent with complex geev
     164      615880 :       DO i = 1, ndim
     165      615880 :          evals(i) = CMPLX(eval1(i), eval2(i), dp)
     166             :       END DO
     167             : 
     168      116673 :    END SUBROUTINE arnoldi_general_local_diag
     169             : 
     170             : END MODULE arnoldi_geev

Generated by: LCOV version 1.15