LCOV - code coverage report
Current view: top level - src - pao_param_exp.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:34ef472) Lines: 109 110 99.1 %
Date: 2024-04-26 08:30:29 Functions: 9 9 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Original matrix exponential parametrization
      10             : !> \author Ole Schuett
      11             : ! **************************************************************************************************
      12             : MODULE pao_param_exp
      13             :    USE basis_set_types,                 ONLY: gto_basis_set_type
      14             :    USE dbcsr_api,                       ONLY: &
      15             :         dbcsr_create, dbcsr_get_block_p, dbcsr_get_info, dbcsr_iterator_blocks_left, &
      16             :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      17             :         dbcsr_p_type, dbcsr_release, dbcsr_reserve_diag_blocks, dbcsr_set, dbcsr_type
      18             :    USE dm_ls_scf_types,                 ONLY: ls_scf_env_type
      19             :    USE kinds,                           ONLY: dp
      20             :    USE mathlib,                         ONLY: diamat_all
      21             :    USE pao_param_methods,               ONLY: pao_calc_AB_from_U,&
      22             :                                               pao_calc_grad_lnv_wrt_U
      23             :    USE pao_potentials,                  ONLY: pao_guess_initial_potential
      24             :    USE pao_types,                       ONLY: pao_env_type
      25             :    USE qs_environment_types,            ONLY: get_qs_env,&
      26             :                                               qs_environment_type
      27             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      28             :                                               qs_kind_type
      29             : #include "./base/base_uses.f90"
      30             : 
      31             :    IMPLICIT NONE
      32             : 
      33             :    PRIVATE
      34             : 
      35             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_param_exp'
      36             : 
      37             :    PUBLIC :: pao_param_init_exp, pao_param_finalize_exp, pao_calc_AB_exp
      38             :    PUBLIC :: pao_param_count_exp, pao_param_initguess_exp
      39             : 
      40             : CONTAINS
      41             : 
      42             : ! **************************************************************************************************
      43             : !> \brief Initialize matrix exponential parametrization
      44             : !> \param pao ...
      45             : !> \param qs_env ...
      46             : ! **************************************************************************************************
      47          24 :    SUBROUTINE pao_param_init_exp(pao, qs_env)
      48             :       TYPE(pao_env_type), POINTER                        :: pao
      49             :       TYPE(qs_environment_type), POINTER                 :: qs_env
      50             : 
      51             :       CHARACTER(len=*), PARAMETER :: routineN = 'pao_param_init_exp'
      52             : 
      53             :       INTEGER                                            :: acol, arow, handle, iatom, N
      54             :       LOGICAL                                            :: found
      55          24 :       REAL(dp), DIMENSION(:), POINTER                    :: H_evals
      56          24 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_H, block_H0, block_N, block_U0, &
      57          24 :                                                             block_V0, H_evecs
      58             :       TYPE(dbcsr_iterator_type)                          :: iter
      59          24 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
      60             : 
      61          24 :       CALL timeset(routineN, handle)
      62             : 
      63          24 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
      64             : 
      65             :       ! allocate matrix_U0
      66             :       CALL dbcsr_create(pao%matrix_U0, &
      67             :                         name="PAO matrix_U0", &
      68             :                         matrix_type="N", &
      69             :                         dist=pao%diag_distribution, &
      70          24 :                         template=matrix_s(1)%matrix)
      71          24 :       CALL dbcsr_reserve_diag_blocks(pao%matrix_U0)
      72             : 
      73             :       ! diagonalize each block of H0 and store eigenvectors in U0
      74             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,qs_env) &
      75          24 : !$OMP PRIVATE(iter,arow,acol,iatom,N,found,block_H0,block_V0,block_N,block_H,block_U0,H_evecs,H_evals)
      76             :       CALL dbcsr_iterator_start(iter, pao%matrix_U0)
      77             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
      78             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_U0)
      79             :          iatom = arow; CPASSERT(arow == acol)
      80             :          CALL dbcsr_get_block_p(matrix=pao%matrix_H0, row=iatom, col=iatom, block=block_H0, found=found)
      81             :          CALL dbcsr_get_block_p(matrix=pao%matrix_N_diag, row=iatom, col=iatom, block=block_N, found=found)
      82             :          CPASSERT(ASSOCIATED(block_H0) .AND. ASSOCIATED(block_N))
      83             :          N = SIZE(block_U0, 1)
      84             : 
      85             :          ALLOCATE (block_V0(N, N))
      86             :          CALL pao_guess_initial_potential(qs_env, iatom, block_V0)
      87             : 
      88             :          ! construct H
      89             :          ALLOCATE (block_H(N, N))
      90             :          block_H = MATMUL(MATMUL(block_N, block_H0 + block_V0), block_N) ! transform into orthonormal basis
      91             : 
      92             :          ! diagonalize H
      93             :          ALLOCATE (H_evecs(N, N), H_evals(N))
      94             :          H_evecs = block_H
      95             :          CALL diamat_all(H_evecs, H_evals)
      96             : 
      97             :          ! use eigenvectors as initial guess
      98             :          block_U0 = H_evecs
      99             : 
     100             :          DEALLOCATE (block_H, H_evecs, H_evals, block_V0)
     101             :       END DO
     102             :       CALL dbcsr_iterator_stop(iter)
     103             : !$OMP END PARALLEL
     104             : 
     105          24 :       IF (pao%precondition) &
     106           0 :          CPABORT("PAO preconditioning not supported for selected parametrization.")
     107             : 
     108          24 :       CALL timestop(handle)
     109          24 :    END SUBROUTINE pao_param_init_exp
     110             : 
     111             : ! **************************************************************************************************
     112             : !> \brief Finalize exponential parametrization
     113             : !> \param pao ...
     114             : ! **************************************************************************************************
     115          24 :    SUBROUTINE pao_param_finalize_exp(pao)
     116             :       TYPE(pao_env_type), POINTER                        :: pao
     117             : 
     118          24 :       CALL dbcsr_release(pao%matrix_U0)
     119             : 
     120          24 :    END SUBROUTINE pao_param_finalize_exp
     121             : 
     122             : ! **************************************************************************************************
     123             : !> \brief Returns the number of parameters for given atomic kind
     124             : !> \param qs_env ...
     125             : !> \param ikind ...
     126             : !> \param nparams ...
     127             : ! **************************************************************************************************
     128         128 :    SUBROUTINE pao_param_count_exp(qs_env, ikind, nparams)
     129             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     130             :       INTEGER, INTENT(IN)                                :: ikind
     131             :       INTEGER, INTENT(OUT)                               :: nparams
     132             : 
     133             :       INTEGER                                            :: cols, pao_basis_size, pri_basis_size, &
     134             :                                                             rows
     135             :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     136          64 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     137             : 
     138          64 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
     139             :       CALL get_qs_kind(qs_kind_set(ikind), &
     140             :                        basis_set=basis_set, &
     141          64 :                        pao_basis_size=pao_basis_size)
     142          64 :       pri_basis_size = basis_set%nsgf
     143             : 
     144             :       ! we only consider rotations between occupied and virtuals
     145          64 :       rows = pao_basis_size
     146          64 :       cols = pri_basis_size - pao_basis_size
     147          64 :       nparams = rows*cols
     148             : 
     149          64 :    END SUBROUTINE pao_param_count_exp
     150             : 
     151             : ! **************************************************************************************************
     152             : !> \brief Fills matrix_X with an initial guess
     153             : !> \param pao ...
     154             : ! **************************************************************************************************
     155          14 :    SUBROUTINE pao_param_initguess_exp(pao)
     156             :       TYPE(pao_env_type), POINTER                        :: pao
     157             : 
     158          14 :       CALL dbcsr_set(pao%matrix_X, 0.0_dp) ! actual initial guess is matrix_U0
     159             : 
     160          14 :    END SUBROUTINE pao_param_initguess_exp
     161             : 
     162             : ! **************************************************************************************************
     163             : !> \brief Takes current matrix_X and calculates the matrices A and B.
     164             : !> \param pao ...
     165             : !> \param qs_env ...
     166             : !> \param ls_scf_env ...
     167             : !> \param gradient ...
     168             : ! **************************************************************************************************
     169        2710 :    SUBROUTINE pao_calc_AB_exp(pao, qs_env, ls_scf_env, gradient)
     170             :       TYPE(pao_env_type), POINTER                        :: pao
     171             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     172             :       TYPE(ls_scf_env_type), TARGET                      :: ls_scf_env
     173             :       LOGICAL, INTENT(IN)                                :: gradient
     174             : 
     175             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pao_calc_AB_exp'
     176             : 
     177             :       INTEGER                                            :: handle
     178        2710 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     179             :       TYPE(dbcsr_type)                                   :: matrix_M, matrix_U
     180             : 
     181        2710 :       CALL timeset(routineN, handle)
     182        2710 :       CALL get_qs_env(qs_env, matrix_s=matrix_s)
     183        2710 :       CALL dbcsr_create(matrix_U, matrix_type="N", dist=pao%diag_distribution, template=matrix_s(1)%matrix)
     184        2710 :       CALL dbcsr_reserve_diag_blocks(matrix_U)
     185             : 
     186             :       !TODO: move this condition into pao_calc_U, use matrix_N as template
     187        2710 :       IF (gradient) THEN
     188         488 :          CALL pao_calc_grad_lnv_wrt_U(qs_env, ls_scf_env, matrix_M)
     189         488 :          CALL pao_calc_U_exp(pao, matrix_U, matrix_M, pao%matrix_G)
     190         488 :          CALL dbcsr_release(matrix_M)
     191             :       ELSE
     192        2222 :          CALL pao_calc_U_exp(pao, matrix_U)
     193             :       END IF
     194             : 
     195        2710 :       CALL pao_calc_AB_from_U(pao, qs_env, ls_scf_env, matrix_U)
     196        2710 :       CALL dbcsr_release(matrix_U)
     197        2710 :       CALL timestop(handle)
     198        2710 :    END SUBROUTINE pao_calc_AB_exp
     199             : 
     200             : ! **************************************************************************************************
     201             : !> \brief Calculate new matrix U and optionally its gradient G
     202             : !> \param pao ...
     203             : !> \param matrix_U ...
     204             : !> \param matrix_M ...
     205             : !> \param matrix_G ...
     206             : ! **************************************************************************************************
     207        2710 :    SUBROUTINE pao_calc_U_exp(pao, matrix_U, matrix_M, matrix_G)
     208             :       TYPE(pao_env_type), POINTER                        :: pao
     209             :       TYPE(dbcsr_type)                                   :: matrix_U
     210             :       TYPE(dbcsr_type), OPTIONAL                         :: matrix_M, matrix_G
     211             : 
     212             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pao_calc_U_exp'
     213             : 
     214             :       COMPLEX(dp)                                        :: denom
     215        2710 :       COMPLEX(dp), DIMENSION(:), POINTER                 :: evals
     216        2710 :       COMPLEX(dp), DIMENSION(:, :), POINTER              :: block_D, evecs
     217             :       INTEGER                                            :: acol, arow, handle, i, iatom, j, k, M, &
     218             :                                                             N, nparams
     219        2710 :       INTEGER, DIMENSION(:), POINTER                     :: blk_sizes_pao, blk_sizes_pri
     220             :       LOGICAL                                            :: found
     221        2710 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_G, block_G_full, block_M, &
     222        2710 :                                                             block_tmp, block_U, block_U0, block_X, &
     223        2710 :                                                             block_X_full
     224             :       TYPE(dbcsr_iterator_type)                          :: iter
     225             : 
     226        2710 :       CALL timeset(routineN, handle)
     227             : 
     228        2710 :       CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=blk_sizes_pri, col_blk_size=blk_sizes_pao)
     229             : 
     230             : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,matrix_U,matrix_M,matrix_G,blk_sizes_pri,blk_sizes_pao) &
     231             : !$OMP PRIVATE(iter,arow,acol,iatom,N,M,nparams,i,j,k,found) &
     232             : !$OMP PRIVATE(block_X,block_U,block_U0,block_X_full,evals,evecs) &
     233        2710 : !$OMP PRIVATE(block_M,block_G,block_D,block_tmp,block_G_full,denom)
     234             :       CALL dbcsr_iterator_start(iter, pao%matrix_X)
     235             :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     236             :          CALL dbcsr_iterator_next_block(iter, arow, acol, block_X)
     237             :          iatom = arow; CPASSERT(arow == acol)
     238             :          CALL dbcsr_get_block_p(matrix=matrix_U, row=iatom, col=iatom, block=block_U, found=found)
     239             :          CPASSERT(ASSOCIATED(block_U))
     240             :          CALL dbcsr_get_block_p(matrix=pao%matrix_U0, row=iatom, col=iatom, block=block_U0, found=found)
     241             :          CPASSERT(ASSOCIATED(block_U0))
     242             : 
     243             :          N = blk_sizes_pri(iatom) ! size of primary basis
     244             :          M = blk_sizes_pao(iatom) ! size of pao basis
     245             :          nparams = SIZE(block_X, 1)
     246             : 
     247             :          ! block_X stores only rotations between occupied and virtuals
     248             :          ! hence, we first have to build the full anti-symmetric exponent block
     249             :          ALLOCATE (block_X_full(N, N))
     250             :          block_X_full(:, :) = 0.0_dp
     251             :          DO i = 1, nparams
     252             :             block_X_full(MOD(i - 1, M) + 1, M + (i - 1)/M + 1) = +block_X(i, 1)
     253             :             block_X_full(M + (i - 1)/M + 1, MOD(i - 1, M) + 1) = -block_X(i, 1)
     254             :          END DO
     255             : 
     256             :          ! diagonalize block_X_full
     257             :          ALLOCATE (evals(N), evecs(N, N))
     258             :          CALL diag_antisym(block_X_full, evecs, evals)
     259             : 
     260             :          ! construct rotation matrix
     261             :          block_U(:, :) = 0.0_dp
     262             :          DO k = 1, N
     263             :             DO i = 1, N
     264             :                DO j = 1, N
     265             :                   block_U(i, j) = block_U(i, j) + REAL(EXP(evals(k))*evecs(i, k)*CONJG(evecs(j, k)), dp)
     266             :                END DO
     267             :             END DO
     268             :          END DO
     269             : 
     270             :          block_U = MATMUL(block_U0, block_U) ! prepend initial guess rotation
     271             : 
     272             :          ! TURNING POINT (if calc grad) ------------------------------------------
     273             :          IF (PRESENT(matrix_G)) THEN
     274             :             CPASSERT(PRESENT(matrix_M))
     275             : 
     276             :             CALL dbcsr_get_block_p(matrix=pao%matrix_G, row=iatom, col=iatom, block=block_G, found=found)
     277             :             CPASSERT(ASSOCIATED(block_G))
     278             :             CALL dbcsr_get_block_p(matrix=matrix_M, row=iatom, col=iatom, block=block_M, found=found)
     279             :             ! don't check ASSOCIATED(block_M), it might have been filtered out.
     280             : 
     281             :             ALLOCATE (block_D(N, N), block_tmp(N, N), block_G_full(N, N))
     282             :             DO i = 1, N
     283             :                DO j = 1, N
     284             :                   denom = evals(i) - evals(j)
     285             :                   IF (i == j) THEN
     286             :                      block_D(i, i) = EXP(evals(i)) ! diagonal elements
     287             :                   ELSE IF (ABS(denom) > 1e-10_dp) THEN
     288             :                      block_D(i, j) = (EXP(evals(i)) - EXP(evals(j)))/denom
     289             :                   ELSE
     290             :                      block_D(i, j) = 1.0_dp ! limit according to L'Hospital's rule
     291             :                   END IF
     292             :                END DO
     293             :             END DO
     294             : 
     295             :             IF (ASSOCIATED(block_M)) THEN
     296             :                block_tmp = MATMUL(TRANSPOSE(block_U0), block_M)
     297             :             ELSE
     298             :                block_tmp = 0.0_dp
     299             :             END IF
     300             :             block_G_full = fold_derivatives(block_tmp, block_D, evecs)
     301             : 
     302             :             ! return only gradient for rotations between occupied and virtuals
     303             :             DO i = 1, nparams
     304             :                block_G(i, 1) = 2.0_dp*block_G_full(MOD(i - 1, M) + 1, M + (i - 1)/M + 1)
     305             :             END DO
     306             : 
     307             :             DEALLOCATE (block_D, block_tmp, block_G_full)
     308             :          END IF
     309             : 
     310             :          DEALLOCATE (block_X_full, evals, evecs)
     311             : 
     312             :       END DO
     313             :       CALL dbcsr_iterator_stop(iter)
     314             : !$OMP END PARALLEL
     315             : 
     316        2710 :       CALL timestop(handle)
     317        2710 :    END SUBROUTINE pao_calc_U_exp
     318             : 
     319             : ! **************************************************************************************************
     320             : !> \brief Helper routine, for calculating derivatives
     321             : !> \param M ...
     322             : !> \param D ...
     323             : !> \param R ...
     324             : !> \return ...
     325             : ! **************************************************************************************************
     326         683 :    FUNCTION fold_derivatives(M, D, R) RESULT(G)
     327             :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: M
     328             :       COMPLEX(dp), DIMENSION(:, :), INTENT(IN)           :: D, R
     329             :       REAL(dp), DIMENSION(SIZE(M, 1), SIZE(M, 1))        :: G
     330             : 
     331         683 :       COMPLEX(dp), DIMENSION(:, :), POINTER              :: F, RF, RM, RMR
     332             :       INTEGER                                            :: n
     333         683 :       REAL(dp), DIMENSION(:, :), POINTER                 :: RFR
     334             : 
     335         683 :       n = SIZE(M, 1)
     336             : 
     337       10928 :       ALLOCATE (RM(n, n), RMR(n, n), F(n, n), RF(n, n), RFR(n, n))
     338             : 
     339      642537 :       RM = MATMUL(TRANSPOSE(CONJG(R)), TRANSPOSE(M))
     340     1133318 :       RMR = MATMUL(RM, R)
     341      101626 :       F = RMR*D !Hadamard product
     342      641854 :       RF = MATMUL(R, F)
     343     1133318 :       RFR = REAL(MATMUL(RF, TRANSPOSE(CONJG(R))), dp)
     344             : 
     345             :       ! gradient dE/dX has to be anti-symmetric
     346       50813 :       G = 0.5_dp*(TRANSPOSE(RFR) - RFR)
     347             : 
     348         683 :       DEALLOCATE (RM, RMR, F, RF, RFR)
     349         683 :    END FUNCTION fold_derivatives
     350             : 
     351             : ! **************************************************************************************************
     352             : !> \brief Helper routine for diagonalizing anti symmetric matrices
     353             : !> \param matrix ...
     354             : !> \param evecs ...
     355             : !> \param evals ...
     356             : ! **************************************************************************************************
     357        3539 :    SUBROUTINE diag_antisym(matrix, evecs, evals)
     358             :       REAL(dp), DIMENSION(:, :)                          :: matrix
     359             :       COMPLEX(dp), DIMENSION(:, :)                       :: evecs
     360             :       COMPLEX(dp), DIMENSION(:)                          :: evals
     361             : 
     362             :       COMPLEX(dp), DIMENSION(:, :), POINTER              :: matrix_c
     363             :       INTEGER                                            :: N
     364             :       REAL(dp), DIMENSION(:), POINTER                    :: evals_r
     365             : 
     366      235869 :       IF (MAXVAL(ABS(matrix + TRANSPOSE(matrix))) > 1e-14_dp) CPABORT("Expected anti-symmetric matrix")
     367        3539 :       N = SIZE(matrix, 1)
     368       21234 :       ALLOCATE (matrix_c(N, N), evals_r(N))
     369             : 
     370      235869 :       matrix_c = CMPLX(0.0_dp, -matrix, kind=dp)
     371        3539 :       CALL zheevd_wrapper(matrix_c, evecs, evals_r)
     372       27874 :       evals = CMPLX(0.0_dp, evals_r, kind=dp)
     373             : 
     374        3539 :       DEALLOCATE (matrix_c, evals_r)
     375        3539 :    END SUBROUTINE diag_antisym
     376             : 
     377             : ! **************************************************************************************************
     378             : !> \brief Helper routine for calling LAPACK zheevd
     379             : !> \param matrix ...
     380             : !> \param eigenvectors ...
     381             : !> \param eigenvalues ...
     382             : ! **************************************************************************************************
     383        3539 :    SUBROUTINE zheevd_wrapper(matrix, eigenvectors, eigenvalues)
     384             :       COMPLEX(dp), DIMENSION(:, :)                       :: matrix, eigenvectors
     385             :       REAL(dp), DIMENSION(:)                             :: eigenvalues
     386             : 
     387             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'zheevd_wrapper'
     388             : 
     389        3539 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER            :: work
     390        3539 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER         :: A
     391             :       INTEGER                                            :: handle, info, liwork, lrwork, lwork, n
     392        3539 :       INTEGER, DIMENSION(:), POINTER                     :: iwork
     393        3539 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rwork
     394             : 
     395        3539 :       CALL timeset(routineN, handle)
     396             : 
     397        3539 :       IF (SIZE(matrix, 1) /= SIZE(matrix, 2)) CPABORT("expected square matrix")
     398      235869 :       IF (MAXVAL(ABS(matrix - CONJG(TRANSPOSE(matrix)))) > 1e-14_dp) CPABORT("Expect hermitian matrix")
     399             : 
     400        3539 :       n = SIZE(matrix, 1)
     401       14156 :       ALLOCATE (iwork(1), rwork(1), work(1), A(n, n))
     402             : 
     403      235869 :       A(:, :) = matrix ! ZHEEVD will overwrite A
     404             :       ! work space query
     405        3539 :       lwork = -1
     406        3539 :       lrwork = -1
     407        3539 :       liwork = -1
     408             : 
     409             :       CALL ZHEEVD('V', 'U', n, A(1, 1), n, eigenvalues(1), &
     410        3539 :                   work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     411        3539 :       lwork = INT(REAL(work(1), dp))
     412        3539 :       lrwork = INT(REAL(rwork(1), dp))
     413        3539 :       liwork = iwork(1)
     414             : 
     415        3539 :       DEALLOCATE (iwork, rwork, work)
     416       10617 :       ALLOCATE (iwork(liwork))
     417      135831 :       iwork(:) = 0
     418       10617 :       ALLOCATE (rwork(lrwork))
     419      544743 :       rwork(:) = 0.0_dp
     420       10617 :       ALLOCATE (work(lwork))
     421      806594 :       work(:) = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
     422             : 
     423             :       CALL ZHEEVD('V', 'U', n, A(1, 1), n, eigenvalues(1), &
     424        3539 :                   work(1), lwork, rwork(1), lrwork, iwork(1), liwork, info)
     425             : 
     426      235869 :       eigenvectors = A
     427             : 
     428        3539 :       IF (info /= 0) CPABORT("diagonalization failed")
     429             : 
     430        3539 :       DEALLOCATE (iwork, rwork, work, A)
     431             : 
     432        3539 :       CALL timestop(handle)
     433             : 
     434        3539 :    END SUBROUTINE zheevd_wrapper
     435             : 
     436         683 : END MODULE pao_param_exp

Generated by: LCOV version 1.15