70#if defined (__parallel)
73#if defined (__HAS_IEEE_EXCEPTIONS)
74 USE ieee_exceptions,
ONLY: ieee_get_halting_mode, &
75 ieee_set_halting_mode, &
78#include "../base/base_uses.f90"
84 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
93 INTEGER,
SAVE :: elpa_neigvec_min = 0
97 INTEGER,
SAVE,
PUBLIC :: dlaf_neigvec_min = 0
101 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
108#if defined(__CUSOLVERMP)
150 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
151 elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
152 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
153 LOGICAL,
INTENT(OUT) :: fallback_applied
154 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
155 LOGICAL,
INTENT(IN) :: elpa_qr, elpa_print, elpa_qr_unsafe
156 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
157 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
159 LOGICAL,
SAVE :: initialized = .false.
161 fallback_applied = .false.
163 IF (diag_lib ==
"ScaLAPACK")
THEN
165 ELSE IF (diag_lib ==
"ELPA")
THEN
172 fallback_applied = .true.
174 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
176 ELSE IF (diag_lib ==
"DLAF")
THEN
180 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
183 cpabort(
"ERROR in diag_init: Initialization of unknown diagonalization library requested")
195 elpa_neigvec_min = elpa_neigvec_min_input
197 dlaf_neigvec_min = dlaf_neigvec_min_input
199 mark_used(dlaf_neigvec_min_input)
201 eps_check_diag = eps_check_diag_input
230 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
231 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
232 INTEGER,
INTENT(OUT),
OPTIONAL :: info
234 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
239 IF (
PRESENT(info)) info = 0
242 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
245 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
247 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
253 IF (matrix%matrix_struct%nrow_global < 64)
THEN
255 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
262 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
264 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
271 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
274 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
284 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
286 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
287 INTEGER,
INTENT(IN) :: nvec
289 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
291 CHARACTER(LEN=default_string_length) :: diag_type_name
292 REAL(kind=
dp) :: eps_abort, eps_warning
293 INTEGER :: handle, i, j, ncol, nrow, output_unit
294 LOGICAL :: check_eigenvectors
295#if defined(__parallel)
297 INTEGER :: il, jl, ipcol, iprow, &
298 mypcol, myprow, npcol, nprow
299 INTEGER,
DIMENSION(9) :: desca
302 CALL timeset(routinen, handle)
305 diag_type_name =
"SYEVD"
307 diag_type_name =
"ELPA"
309 diag_type_name =
"CUSOLVER"
311 diag_type_name =
"DLAF"
313 cpabort(
"Unknown diag_type")
319#if defined(__CHECK_DIAG)
320 check_eigenvectors = .true.
321 IF (eps_check_diag >= 0.0_dp)
THEN
322 eps_warning = eps_check_diag
325 IF (eps_check_diag >= 0.0_dp)
THEN
326 check_eigenvectors = .true.
327 eps_warning = eps_check_diag
329 check_eigenvectors = .false.
332 eps_abort = 10.0_dp*eps_warning
334 IF (check_eigenvectors)
THEN
335#if defined(__parallel)
336 nrow = eigenvectors%matrix_struct%nrow_global
337 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
338 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
339 context => matrix%matrix_struct%context
340 myprow = context%mepos(1)
341 mypcol = context%mepos(2)
342 nprow = context%num_pe(1)
343 npcol = context%num_pe(2)
344 desca(:) = matrix%matrix_struct%descriptor(:)
347 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
348 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
350 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_warning)
THEN
351 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
352 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
353 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
354 "The deviation from the expected value 1 is", abs(matrix%local_data(il, jl) - 1.0_dp)
355 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_abort)
THEN
356 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
358 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
362 IF (abs(matrix%local_data(il, jl)) > eps_warning)
THEN
363 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
364 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
365 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
366 "The deviation from the expected value 0 is", abs(matrix%local_data(il, jl))
367 IF (abs(matrix%local_data(il, jl)) > eps_abort)
THEN
368 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
370 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
378 nrow =
SIZE(eigenvectors%local_data, 1)
379 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
380 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
381 eigenvectors%local_data(1, 1), nrow, &
382 eigenvectors%local_data(1, 1), nrow, &
383 0.0_dp, matrix%local_data(1, 1), nrow)
387 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_warning)
THEN
388 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
389 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
390 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
391 "The deviation from the expected value 1 is", abs(matrix%local_data(i, j) - 1.0_dp)
392 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_abort)
THEN
393 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
395 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
399 IF (abs(matrix%local_data(i, j)) > eps_warning)
THEN
400 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
401 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
402 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
403 "The deviation from the expected value 0 is", abs(matrix%local_data(i, j))
404 IF (abs(matrix%local_data(i, j)) > eps_abort)
THEN
405 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
407 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
416 CALL timestop(handle)
418 END SUBROUTINE check_diag
435 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
436 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
437 INTEGER,
INTENT(OUT),
OPTIONAL :: info
439 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd'
441 INTEGER :: handle, myinfo, n, nmo
442 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
443#if defined(__parallel)
444 TYPE(
cp_fm_type) :: eigenvectors_new, matrix_new
446 CHARACTER(LEN=2*default_string_length) :: message
447 INTEGER :: liwork, lwork, nl
448 INTEGER,
DIMENSION(:),
POINTER :: iwork
449 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
450 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
453 CALL timeset(routinen, handle)
457 n = matrix%matrix_struct%nrow_global
460#if defined(__parallel)
468 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
469 IF (
PRESENT(info))
THEN
470 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
472 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
481 m => matrix%local_data
490 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
492 IF (myinfo /= 0)
THEN
493 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Work space query failed (INFO = ", myinfo,
")"
494 IF (
PRESENT(info))
THEN
495 cpwarn(trim(message))
497 cpabort(trim(message))
504 ALLOCATE (work(lwork))
509 ALLOCATE (iwork(liwork))
512 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
514 IF (myinfo /= 0)
THEN
515 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
516 IF (
PRESENT(info))
THEN
517 cpwarn(trim(message))
519 cpabort(trim(message))
529 IF (
PRESENT(info)) info = myinfo
531 nmo =
SIZE(eigenvalues, 1)
533 eigenvalues(1:n) = eig(1:n)
535 eigenvalues(1:nmo) = eig(1:nmo)
540 CALL check_diag(matrix, eigenvectors, n)
542 CALL timestop(handle)
553 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
555 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
556 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
557 INTEGER,
INTENT(OUT),
OPTIONAL :: info
559 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
561 CHARACTER(LEN=2*default_string_length) :: message
562 INTEGER :: handle, myinfo
563#if defined(__parallel)
565 INTEGER :: liwork, lwork, &
567 INTEGER,
DIMENSION(9) :: descm, descv
568 INTEGER,
DIMENSION(:),
POINTER :: iwork
569 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
570 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
571#if defined (__HAS_IEEE_EXCEPTIONS)
572 LOGICAL,
DIMENSION(5) :: halt
576 CALL timeset(routinen, handle)
580#if defined(__parallel)
582 n = matrix%matrix_struct%nrow_global
583 m => matrix%local_data
584 context => matrix%matrix_struct%context
585 myprow = context%mepos(1)
586 mypcol = context%mepos(2)
587 descm(:) = matrix%matrix_struct%descriptor(:)
589 v => eigenvectors%local_data
590 descv(:) = eigenvectors%matrix_struct%descriptor(:)
592 liwork = 7*n + 8*context%num_pe(2) + 2
593 ALLOCATE (iwork(liwork))
599 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
600 work(1), lwork, iwork(1), liwork, myinfo)
602 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
603 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Work space query failed (INFO = ", myinfo,
")"
604 IF (
PRESENT(info))
THEN
605 cpwarn(trim(message))
607 cpabort(trim(message))
617 lwork = nint(work(1) + 100000)
620 ALLOCATE (work(lwork))
624#if defined (__HAS_IEEE_EXCEPTIONS)
625 CALL ieee_get_halting_mode(ieee_all, halt)
626 CALL ieee_set_halting_mode(ieee_all, .false.)
629 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
630 work(1), lwork, iwork(1), liwork, myinfo)
632#if defined (__HAS_IEEE_EXCEPTIONS)
633 CALL ieee_set_halting_mode(ieee_all, halt)
635 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
636 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
637 IF (
PRESENT(info))
THEN
638 cpwarn(trim(message))
640 cpabort(trim(message))
644 IF (
PRESENT(info)) info = myinfo
650 mark_used(eigenvectors)
651 mark_used(eigenvalues)
653 IF (
PRESENT(info)) info = myinfo
654 message =
"ERROR in "//trim(routinen)// &
655 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support"
656 cpabort(trim(message))
659 CALL timestop(handle)
661 END SUBROUTINE cp_fm_syevd_base
677 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
682 TYPE(
cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
683 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
684 INTEGER,
INTENT(IN),
OPTIONAL :: neig
685 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
687 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
689#if defined(__parallel)
690 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
692 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
697 CHARACTER(LEN=1) :: job_type
698 REAL(kind=
dp) :: abstol, work_syevx_local
699 INTEGER :: handle, info, &
700 liwork, lwork, m, mypcol, &
701 myprow, n, nb, npcol, &
702 nprow, output_unit, &
704 LOGICAL :: ionode, needs_evecs
705 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
706 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
707 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
709 REAL(kind=
dp),
EXTERNAL :: dlamch
711#if defined(__parallel)
712 INTEGER :: nn, np0, npe, nq0, nz
713 INTEGER,
DIMENSION(9) :: desca, descz
714 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
715 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
716 INTEGER,
EXTERNAL :: iceil, numroc
717#if defined (__HAS_IEEE_EXCEPTIONS)
718 LOGICAL,
DIMENSION(5) :: halt
722 INTEGER,
EXTERNAL :: ilaenv
726 n = matrix%matrix_struct%nrow_global
728 IF (
PRESENT(neig)) neig_local = neig
729 IF (neig_local == 0)
RETURN
731 CALL timeset(routinen, handle)
733 needs_evecs =
PRESENT(eigenvectors)
736 ionode = logger%para_env%is_source()
737 n = matrix%matrix_struct%nrow_global
740 work_syevx_local = 1.0_dp
741 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
744 IF (needs_evecs)
THEN
751 abstol = 2.0_dp*dlamch(
"S")
753 context => matrix%matrix_struct%context
754 myprow = context%mepos(1)
755 mypcol = context%mepos(2)
756 nprow = context%num_pe(1)
757 npcol = context%num_pe(2)
760 eigenvalues(:) = 0.0_dp
761#if defined(__parallel)
763 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
764 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
767 a => matrix%local_data
768 desca(:) = matrix%matrix_struct%descriptor(:)
770 IF (needs_evecs)
THEN
771 z => eigenvectors%local_data
772 descz(:) = eigenvectors%matrix_struct%descriptor(:)
775 z => matrix%local_data
782 nb = matrix%matrix_struct%nrow_block
784 np0 = numroc(nn, nb, 0, 0, nprow)
785 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
787 IF (needs_evecs)
THEN
788 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
789 int(work_syevx_local*real((neig_local - 1)*n,
dp))
791 lwork = 5*n + max(5*nn, nb*(np0 + 1))
793 liwork = 6*max(n, npe + 1, 4)
797 ALLOCATE (iclustr(2*npe))
801 ALLOCATE (iwork(liwork))
802 ALLOCATE (work(lwork))
806#if defined (__HAS_IEEE_EXCEPTIONS)
807 CALL ieee_get_halting_mode(ieee_all, halt)
808 CALL ieee_set_halting_mode(ieee_all, .false.)
811 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
812 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
814#if defined (__HAS_IEEE_EXCEPTIONS)
815 CALL ieee_set_halting_mode(ieee_all, halt)
823 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
826 "liwork = ", liwork, &
829 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
831 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
832 "iclustr = ", iclustr
833 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
837 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
850 a => matrix%local_data
851 IF (needs_evecs)
THEN
852 z => eigenvectors%local_data
855 z => matrix%local_data
860 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
861 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
863 lwork = max((nb + 3)*n, 8*n) + n
868 ALLOCATE (iwork(liwork))
869 ALLOCATE (work(lwork))
874 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
875 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
881 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
884 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
887 cpabort(
"Error in DSYEVX (ScaLAPACK)")
897 eigenvalues(1:neig_local) = w(1:neig_local)
900 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
902 CALL timestop(handle)
915 SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
918 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
919 REAL(kind=
dp),
DIMENSION(:),
POINTER, &
920 INTENT(INOUT) :: eigval
921 INTEGER,
INTENT(OUT),
OPTIONAL :: info
923 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_svd'
925 CHARACTER(LEN=2*default_string_length) :: message
926 INTEGER :: handle, n, m, myinfo, lwork
927 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a
929 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: work
931#if defined(__parallel)
932 INTEGER,
DIMENSION(9) :: desca, descu, descvt
934 CALL timeset(routinen, handle)
937 matrix_struct=matrix_a%matrix_struct, &
940 a => matrix_lu%local_data
941 m = matrix_lu%matrix_struct%nrow_global
942 n = matrix_lu%matrix_struct%ncol_global
951#if defined(__parallel)
953 desca(:) = matrix_lu%matrix_struct%descriptor(:)
954 descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
955 descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
958 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
959 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
961 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
962 WRITE (message,
"(A,I0,A)")
"ERROR in PDGESVD: Work space query failed (INFO = ", myinfo,
")"
963 IF (
PRESENT(info))
THEN
964 cpwarn(trim(message))
966 cpabort(trim(message))
972 ALLOCATE (work(lwork))
974 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
975 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
977 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
978 WRITE (message,
"(A,I0,A)")
"ERROR in PDGESVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
979 IF (
PRESENT(info))
THEN
980 cpwarn(trim(message))
982 cpabort(trim(message))
987 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
988 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
990 IF (myinfo /= 0)
THEN
991 WRITE (message,
"(A,I0,A)")
"ERROR in DGESVD: Work space query failed (INFO = ", myinfo,
")"
992 IF (
PRESENT(info))
THEN
993 cpwarn(trim(message))
995 cpabort(trim(message))
1000 lwork = int(work(1))
1002 ALLOCATE (work(lwork))
1005 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
1006 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
1008 IF (myinfo /= 0)
THEN
1009 WRITE (message,
"(A,I0,A)")
"ERROR in DGESVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
1010 IF (
PRESENT(info))
THEN
1011 cpwarn(trim(message))
1013 cpabort(trim(message))
1022 IF (
PRESENT(info)) info = myinfo
1024 CALL timestop(handle)
1037 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
1047 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
1048 INTEGER,
INTENT(OUT) :: n_dependent
1049 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
1050 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
1053 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
1055 INTEGER :: handle, icol_global, &
1057 ncol_global, npcol, nprow, &
1059 LOGICAL :: my_verbose
1060 REAL(kind=
dp) :: condition_number, f, p
1061 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
1062 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
1065#if defined(__parallel)
1066 INTEGER :: icol_local, ipcol, iprow, irow_global, &
1070 CALL timeset(routinen, handle)
1072 my_verbose = .false.
1073 IF (
PRESENT(verbose)) my_verbose = verbose
1075 context => matrix%matrix_struct%context
1076 myprow = context%mepos(1)
1077 mypcol = context%mepos(2)
1078 nprow = context%num_pe(1)
1079 npcol = context%num_pe(2)
1083 nrow_global = matrix%matrix_struct%nrow_global
1084 ncol_global = matrix%matrix_struct%ncol_global
1086 ALLOCATE (eigenvalues(ncol_global))
1088 eigenvalues(:) = 0.0_dp
1094 IF (
PRESENT(eigvals))
THEN
1095 eigvals(1) = eigenvalues(1)
1096 eigvals(2) = eigenvalues(ncol_global)
1099#if defined(__parallel)
1100 eigenvectors => work%local_data
1104 DO icol_global = 1, ncol_global
1106 IF (eigenvalues(icol_global) < threshold)
THEN
1108 n_dependent = n_dependent + 1
1110 ipcol = work%matrix_struct%g2p_col(icol_global)
1112 IF (mypcol == ipcol)
THEN
1113 icol_local = work%matrix_struct%g2l_col(icol_global)
1114 DO irow_global = 1, nrow_global
1115 iprow = work%matrix_struct%g2p_row(irow_global)
1116 IF (myprow == iprow)
THEN
1117 irow_local = work%matrix_struct%g2l_row(irow_global)
1118 eigenvectors(irow_local, icol_local) = 0.0_dp
1125 f = eigenvalues(icol_global)**p
1127 ipcol = work%matrix_struct%g2p_col(icol_global)
1129 IF (mypcol == ipcol)
THEN
1130 icol_local = work%matrix_struct%g2l_col(icol_global)
1131 DO irow_global = 1, nrow_global
1132 iprow = work%matrix_struct%g2p_row(irow_global)
1133 IF (myprow == iprow)
THEN
1134 irow_local = work%matrix_struct%g2l_row(irow_global)
1135 eigenvectors(irow_local, icol_local) = &
1136 f*eigenvectors(irow_local, icol_local)
1147 eigenvectors => work%local_data
1151 DO icol_global = 1, ncol_global
1153 IF (eigenvalues(icol_global) < threshold)
THEN
1155 n_dependent = n_dependent + 1
1156 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1160 f = eigenvalues(icol_global)**p
1161 eigenvectors(1:nrow_global, icol_global) = &
1162 f*eigenvectors(1:nrow_global, icol_global)
1169 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1173 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1174 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1176 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1177 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1178 "CP_FM_POWER: condition number: ", condition_number
1179 IF (eigenvalues(1) <= 0.0_dp)
THEN
1181 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1183 IF (condition_number > 1.0e12_dp)
THEN
1185 "WARNING: high condition number => possibly ill-conditioned matrix"
1189 DEALLOCATE (eigenvalues)
1191 CALL timestop(handle)
1215 TYPE(
cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1216 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1217 INTEGER,
INTENT(IN) :: start_sec_block
1218 REAL(kind=
dp),
INTENT(IN) :: thresh
1220 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1223 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1225 REAL(kind=
dp) :: tan_theta, tau, c, s
1227 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1229#if defined(__parallel)
1232 INTEGER :: myprow, mypcol, nprow, npcol, block_dim_row, block_dim_col, &
1233 info, ev_row_block_size, iam, mynumrows, mype, npe, &
1235 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1236 INTEGER,
DIMENSION(9) :: desca, descz, desc_a_block, &
1240 INTEGER,
EXTERNAL :: numroc
1245 CALL timeset(routinen, handle)
1247#if defined(__parallel)
1248 context => matrix%matrix_struct%context
1249 allgrp = matrix%matrix_struct%para_env
1251 myprow = context%mepos(1)
1252 mypcol = context%mepos(2)
1253 nprow = context%num_pe(1)
1254 npcol = context%num_pe(2)
1256 n = matrix%matrix_struct%nrow_global
1258 a => matrix%local_data
1259 desca(:) = matrix%matrix_struct%descriptor(:)
1260 ev => eigenvectors%local_data
1261 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1267 block_dim_row = start_sec_block - 1
1268 block_dim_col = n - block_dim_row
1269 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1271 mype = matrix%matrix_struct%para_env%mepos
1272 npe = matrix%matrix_struct%para_env%num_pe
1274 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1276 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1277 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1279 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1280 a_loc, 1, 1, desc_a_block, context%get_handle())
1282 CALL allgrp%bcast(a_loc, 0)
1289 ev_row_block_size = n/(nprow*npcol)
1290 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1292 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1294 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1297 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1303 DO q = start_sec_block, n
1305 DO p = 1, (start_sec_block - 1)
1307 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1309 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1311 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1314 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1322 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1323 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1324 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1325 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1326 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1334 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1337 DEALLOCATE (a_loc, ev_loc, c_ip)
1339 CALL ictxt_loc%gridexit()
1343 n = matrix%matrix_struct%nrow_global
1347 a => matrix%local_data
1348 ev => eigenvectors%local_data
1355 DO q = start_sec_block, n
1356 DO p = 1, (start_sec_block - 1)
1358 IF (abs(a(p, q)) > thresh)
THEN
1360 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1362 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1365 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1373 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1374 CALL dscal(n, c, ev(1, p), 1)
1375 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1376 CALL dscal(n, c, ev(1, q), 1)
1377 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1390 CALL timestop(handle)
1403 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1405 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1406 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1409 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1411 INTEGER :: handle, nao, nmo
1413 CALL timeset(routinen, handle)
1416 nmo =
SIZE(eigenvalues)
1436 eigenvalues=eigenvalues)
1442 CALL timestop(handle)
1458 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1459 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1461 REAL(kind=
dp),
INTENT(IN) :: epseig
1463 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1465 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1467 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: evals
1469 CALL timeset(routinen, handle)
1473 nmo =
SIZE(eigenvalues)
1474 ALLOCATE (evals(nao))
1479 evals(:) = -evals(:)
1482 IF (evals(i) < epseig)
THEN
1493 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1496 DO icol = nc + 1, nao
1502 evals(nc + 1:nao) = 1.0_dp
1505 evals(:) = 1.0_dp/sqrt(evals(:))
1508 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1509 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1512 DO icol = nc + 1, nao
1517 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1520 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1524 CALL timestop(handle)
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
methods related to the blacs parallel environment
wrappers for the actual blacs calls. all functionality needed in the code should actually be provide ...
basic linear algebra operations for full matrices
subroutine, public cp_fm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, c_first_row)
computes matrix_c = beta * matrix_c + alpha * ( matrix_a ** transa ) * ( matrix_b ** transb )
subroutine, public cp_fm_column_scale(matrixa, scaling)
scales column i of matrix a with scaling(i)
subroutine, public cp_fm_syrk(uplo, trans, k, alpha, matrix_a, ia, ja, beta, matrix_c)
performs a rank-k update of a symmetric matrix_c matrix_c = beta * matrix_c + alpha * matrix_a * tran...
subroutine, public cp_fm_uplo_to_full(matrix, work, uplo)
given a triangular matrix according to uplo, computes the corresponding full matrix
subroutine, public cp_fm_scale(alpha, matrix_a)
scales a matrix matrix_a = alpha * matrix_b
subroutine, public cp_fm_triangular_invert(matrix_a, uplo_tr)
inverts a triangular matrix
subroutine, public cp_fm_triangular_multiply(triangular_matrix, matrix_b, side, transpose_tr, invert_tr, uplo_tr, unit_diag_tr, n_rows, n_cols, alpha)
multiplies in place by a triangular matrix: matrix_b = alpha op(triangular_matrix) matrix_b or (if si...
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_decompose(matrix, n, info_out)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
subroutine, public cp_fm_general_cusolver(amatrix, bmatrix, eigenvectors, eigenvalues)
Driver routine to solve generalized eigenvalue problem A*x = lambda*B*x with cuSOLVERMp.
subroutine, public cp_fm_diag_cusolver(matrix, eigenvectors, eigenvalues)
Driver routine to diagonalize a FM matrix with the cuSOLVERMp library.
Auxiliary tools to redistribute cp_fm_type matrices before and after diagonalization....
subroutine, public cp_fm_redistribute_end(matrix, eigenvectors, eig, matrix_new, eigenvectors_new)
Redistributes eigenvectors and eigenvalues back to the original communicator group.
subroutine, public cp_fm_redistribute_start(matrix, eigenvectors, matrix_new, eigenvectors_new, caller_is_elpa, redist_info)
Determines the optimal number of CPUs for matrix diagonalization and redistributes the input matrices...
used for collecting some of the diagonalization schemes available for cp_fm_type. cp_fm_power also mo...
subroutine, public cp_fm_block_jacobi(matrix, eigenvectors, eigval, thresh, start_sec_block)
...
real(kind=dp), parameter, public eps_check_diag_default
subroutine, public cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
...
integer, parameter, public fm_diag_type_cusolver
subroutine, public cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
decomposes a quadratic matrix into its singular value decomposition
integer, parameter, public fm_diag_type_dlaf
integer, parameter, public fm_diag_type_scalapack
subroutine, public cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
Computes all eigenvalues and vectors of a real symmetric matrix significantly faster than syevx,...
subroutine, public diag_finalize()
Finalize the diagonalization library.
subroutine, public diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
Setup the diagonalization library to be used.
integer, parameter, public fm_diag_type_default
subroutine, public cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
General Eigenvalue Problem AX = BXE Single option version: Cholesky decomposition of B.
subroutine, public choose_eigv_solver(matrix, eigenvectors, eigenvalues, info)
Choose the Eigensolver depending on which library is available ELPA seems to be unstable for small sy...
integer, save, public diag_type
integer, parameter, public fm_diag_type_elpa
subroutine, public cp_fm_geeig_canon(amatrix, bmatrix, eigenvectors, eigenvalues, work, epseig)
General Eigenvalue Problem AX = BXE Use canonical diagonalization : U*s**(-1/2)
subroutine, public cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
compute eigenvalues and optionally eigenvectors of a real symmetric matrix using scalapack....
subroutine, public cp_fm_diag_dlaf(matrix, eigenvectors, eigenvalues)
...
subroutine, public cp_fm_diag_gen_dlaf(a_matrix, b_matrix, eigenvectors, eigenvalues)
...
subroutine, public set_elpa_print(flag)
Sets a flag that determines if additional information about the ELPA diagonalization should be printe...
subroutine, public set_elpa_kernel(requested_kernel)
Sets the active ELPA kernel.
subroutine, public cp_fm_diag_elpa(matrix, eigenvectors, eigenvalues)
Driver routine to diagonalize a FM matrix with the ELPA library.
subroutine, public set_elpa_qr(use_qr, use_qr_unsafe)
Sets flags that determines if ELPA should try to use QR during diagonalization If use_qr = ....
subroutine, public initialize_elpa_library()
Initialize the ELPA library.
subroutine, public finalize_elpa_library()
Finalize the ELPA library.
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
logical function, public cp_fm_struct_equivalent(fmstruct1, fmstruct2)
returns true if the two matrix structures are equivalent, false otherwise.
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_to_fm_submat(msource, mtarget, nrow, ncol, s_firstrow, s_firstcol, t_firstrow, t_firstcol)
copy just a part ot the matrix
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
subroutine, public cp_fm_set_element(matrix, irow_global, icol_global, alpha)
sets an element of a matrix
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp)
creates a new full matrix with the given structure
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
integer function, public cp_logger_get_unit_nr(logger, local)
returns the unit nr for the requested kind of log.
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_string_length
Machine interface based on Fortran 2003 and POSIX.
integer, parameter, public default_output_unit
subroutine, public m_memory(mem)
Returns the total amount of memory [bytes] in use, if known, zero otherwise.
Interface to the message passing library MPI.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...