71#if defined (__parallel)
74#if defined (__HAS_IEEE_EXCEPTIONS)
75 USE ieee_exceptions,
ONLY: ieee_get_halting_mode, &
76 ieee_set_halting_mode, &
79#include "../base/base_uses.f90"
85 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
94 INTEGER,
SAVE :: elpa_neigvec_min = 0
98 INTEGER,
SAVE,
PUBLIC :: dlaf_neigvec_min = 0
102 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
109#if defined(__CUSOLVERMP)
151 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
152 elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
153 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
154 LOGICAL,
INTENT(OUT) :: fallback_applied
155 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
156 LOGICAL,
INTENT(IN) :: elpa_qr, elpa_print, elpa_qr_unsafe
157 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
158 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
160 LOGICAL,
SAVE :: initialized = .false.
162 fallback_applied = .false.
164 IF (diag_lib ==
"ScaLAPACK")
THEN
166 ELSE IF (diag_lib ==
"ELPA")
THEN
173 fallback_applied = .true.
175 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
177 ELSE IF (diag_lib ==
"DLAF")
THEN
181 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
184 cpabort(
"ERROR in diag_init: Initialization of unknown diagonalization library requested")
200 dlaf_neigvec_min = dlaf_neigvec_min_input
202 mark_used(dlaf_neigvec_min_input)
205 elpa_neigvec_min = elpa_neigvec_min_input
206 eps_check_diag = eps_check_diag_input
239 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
240 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
241 INTEGER,
INTENT(OUT),
OPTIONAL :: info
243 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
248 IF (
PRESENT(info)) info = 0
251 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
254 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
256 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
262 IF (matrix%matrix_struct%nrow_global < 64)
THEN
264 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
271 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
273 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
280 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
283 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
293 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
295 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
296 INTEGER,
INTENT(IN) :: nvec
298 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
300 CHARACTER(LEN=default_string_length) :: diag_type_name
301 REAL(kind=
dp) :: eps_abort, eps_warning
302 INTEGER :: handle, i, j, ncol, nrow, output_unit
303 LOGICAL :: check_eigenvectors
304#if defined(__parallel)
306 INTEGER :: il, jl, ipcol, iprow, &
307 mypcol, myprow, npcol, nprow
308 INTEGER,
DIMENSION(9) :: desca
311 CALL timeset(routinen, handle)
314 diag_type_name =
"SYEVD"
316 diag_type_name =
"ELPA"
318 diag_type_name =
"CUSOLVER"
320 diag_type_name =
"DLAF"
322 cpabort(
"Unknown diag_type")
328#if defined(__CHECK_DIAG)
329 check_eigenvectors = .true.
330 IF (eps_check_diag >= 0.0_dp)
THEN
331 eps_warning = eps_check_diag
334 IF (eps_check_diag >= 0.0_dp)
THEN
335 check_eigenvectors = .true.
336 eps_warning = eps_check_diag
338 check_eigenvectors = .false.
341 eps_abort = 10.0_dp*eps_warning
343 IF (check_eigenvectors)
THEN
344#if defined(__parallel)
345 nrow = eigenvectors%matrix_struct%nrow_global
346 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
347 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
348 context => matrix%matrix_struct%context
349 myprow = context%mepos(1)
350 mypcol = context%mepos(2)
351 nprow = context%num_pe(1)
352 npcol = context%num_pe(2)
353 desca(:) = matrix%matrix_struct%descriptor(:)
356 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
357 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
359 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_warning)
THEN
360 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
361 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
362 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
363 "The deviation from the expected value 1 is", abs(matrix%local_data(il, jl) - 1.0_dp)
364 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_abort)
THEN
365 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
367 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
371 IF (abs(matrix%local_data(il, jl)) > eps_warning)
THEN
372 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
373 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
374 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
375 "The deviation from the expected value 0 is", abs(matrix%local_data(il, jl))
376 IF (abs(matrix%local_data(il, jl)) > eps_abort)
THEN
377 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
379 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
387 nrow =
SIZE(eigenvectors%local_data, 1)
388 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
389 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
390 eigenvectors%local_data(1, 1), nrow, &
391 eigenvectors%local_data(1, 1), nrow, &
392 0.0_dp, matrix%local_data(1, 1), nrow)
396 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_warning)
THEN
397 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
398 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
399 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
400 "The deviation from the expected value 1 is", abs(matrix%local_data(i, j) - 1.0_dp)
401 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_abort)
THEN
402 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
404 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
408 IF (abs(matrix%local_data(i, j)) > eps_warning)
THEN
409 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
410 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
411 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
412 "The deviation from the expected value 0 is", abs(matrix%local_data(i, j))
413 IF (abs(matrix%local_data(i, j)) > eps_abort)
THEN
414 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
416 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
425 CALL timestop(handle)
427 END SUBROUTINE check_diag
444 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
445 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
446 INTEGER,
INTENT(OUT),
OPTIONAL :: info
448 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd'
450 INTEGER :: handle, myinfo, n, nmo
451 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
452#if defined(__parallel)
453 TYPE(
cp_fm_type) :: eigenvectors_new, matrix_new
455 CHARACTER(LEN=2*default_string_length) :: message
456 INTEGER :: liwork, lwork, nl
457 INTEGER,
DIMENSION(:),
POINTER :: iwork
458 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
459 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
462 CALL timeset(routinen, handle)
466 n = matrix%matrix_struct%nrow_global
469#if defined(__parallel)
477 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
478 IF (
PRESENT(info))
THEN
479 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
481 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
490 m => matrix%local_data
499 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
501 IF (myinfo /= 0)
THEN
502 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Work space query failed (INFO = ", myinfo,
")"
503 IF (
PRESENT(info))
THEN
504 cpwarn(trim(message))
506 cpabort(trim(message))
513 ALLOCATE (work(lwork))
518 ALLOCATE (iwork(liwork))
521 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
523 IF (myinfo /= 0)
THEN
524 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
525 IF (
PRESENT(info))
THEN
526 cpwarn(trim(message))
528 cpabort(trim(message))
538 IF (
PRESENT(info)) info = myinfo
540 nmo =
SIZE(eigenvalues, 1)
542 eigenvalues(1:n) = eig(1:n)
544 eigenvalues(1:nmo) = eig(1:nmo)
549 CALL check_diag(matrix, eigenvectors, n)
551 CALL timestop(handle)
562 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
564 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
565 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
566 INTEGER,
INTENT(OUT),
OPTIONAL :: info
568 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
570 CHARACTER(LEN=2*default_string_length) :: message
571 INTEGER :: handle, myinfo
572#if defined(__parallel)
574 INTEGER :: liwork, lwork, &
576 INTEGER,
DIMENSION(9) :: descm, descv
577 INTEGER,
DIMENSION(:),
POINTER :: iwork
578 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
579 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
580#if defined (__HAS_IEEE_EXCEPTIONS)
581 LOGICAL,
DIMENSION(5) :: halt
585 CALL timeset(routinen, handle)
589#if defined(__parallel)
591 n = matrix%matrix_struct%nrow_global
592 m => matrix%local_data
593 context => matrix%matrix_struct%context
594 myprow = context%mepos(1)
595 mypcol = context%mepos(2)
596 descm(:) = matrix%matrix_struct%descriptor(:)
598 v => eigenvectors%local_data
599 descv(:) = eigenvectors%matrix_struct%descriptor(:)
601 liwork = 7*n + 8*context%num_pe(2) + 2
602 ALLOCATE (iwork(liwork))
608 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
609 work(1), lwork, iwork(1), liwork, myinfo)
611 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
612 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Work space query failed (INFO = ", myinfo,
")"
613 IF (
PRESENT(info))
THEN
614 cpwarn(trim(message))
616 cpabort(trim(message))
626 lwork = nint(work(1) + 100000)
629 ALLOCATE (work(lwork))
633#if defined (__HAS_IEEE_EXCEPTIONS)
634 CALL ieee_get_halting_mode(ieee_all, halt)
635 CALL ieee_set_halting_mode(ieee_all, .false.)
638 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
639 work(1), lwork, iwork(1), liwork, myinfo)
641#if defined (__HAS_IEEE_EXCEPTIONS)
642 CALL ieee_set_halting_mode(ieee_all, halt)
644 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
645 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
646 IF (
PRESENT(info))
THEN
647 cpwarn(trim(message))
649 cpabort(trim(message))
653 IF (
PRESENT(info)) info = myinfo
659 mark_used(eigenvectors)
660 mark_used(eigenvalues)
662 IF (
PRESENT(info)) info = myinfo
663 message =
"ERROR in "//trim(routinen)// &
664 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support"
665 cpabort(trim(message))
668 CALL timestop(handle)
670 END SUBROUTINE cp_fm_syevd_base
686 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
691 TYPE(
cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
692 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
693 INTEGER,
INTENT(IN),
OPTIONAL :: neig
694 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
696 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
698#if defined(__parallel)
699 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
701 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
706 CHARACTER(LEN=1) :: job_type
707 REAL(kind=
dp) :: abstol, work_syevx_local
708 INTEGER :: handle, info, &
709 liwork, lwork, m, mypcol, &
710 myprow, n, nb, npcol, &
711 nprow, output_unit, &
713 LOGICAL :: ionode, needs_evecs
714 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
715 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
716 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
718 REAL(kind=
dp),
EXTERNAL :: dlamch
720#if defined(__parallel)
721 INTEGER :: nn, np0, npe, nq0, nz
722 INTEGER,
DIMENSION(9) :: desca, descz
723 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
724 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
725 INTEGER,
EXTERNAL :: iceil, numroc
726#if defined (__HAS_IEEE_EXCEPTIONS)
727 LOGICAL,
DIMENSION(5) :: halt
731 INTEGER,
EXTERNAL :: ilaenv
735 n = matrix%matrix_struct%nrow_global
737 IF (
PRESENT(neig)) neig_local = neig
738 IF (neig_local == 0)
RETURN
740 CALL timeset(routinen, handle)
742 needs_evecs =
PRESENT(eigenvectors)
745 ionode = logger%para_env%is_source()
746 n = matrix%matrix_struct%nrow_global
749 work_syevx_local = 1.0_dp
750 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
753 IF (needs_evecs)
THEN
760 abstol = 2.0_dp*dlamch(
"S")
762 context => matrix%matrix_struct%context
763 myprow = context%mepos(1)
764 mypcol = context%mepos(2)
765 nprow = context%num_pe(1)
766 npcol = context%num_pe(2)
769 eigenvalues(:) = 0.0_dp
770#if defined(__parallel)
772 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
773 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
776 a => matrix%local_data
777 desca(:) = matrix%matrix_struct%descriptor(:)
779 IF (needs_evecs)
THEN
780 z => eigenvectors%local_data
781 descz(:) = eigenvectors%matrix_struct%descriptor(:)
784 z => matrix%local_data
791 nb = matrix%matrix_struct%nrow_block
793 np0 = numroc(nn, nb, 0, 0, nprow)
794 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
796 IF (needs_evecs)
THEN
797 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
798 int(work_syevx_local*real((neig_local - 1)*n,
dp))
800 lwork = 5*n + max(5*nn, nb*(np0 + 1))
802 liwork = 6*max(n, npe + 1, 4)
806 ALLOCATE (iclustr(2*npe))
810 ALLOCATE (iwork(liwork))
811 ALLOCATE (work(lwork))
815#if defined (__HAS_IEEE_EXCEPTIONS)
816 CALL ieee_get_halting_mode(ieee_all, halt)
817 CALL ieee_set_halting_mode(ieee_all, .false.)
820 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
821 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
823#if defined (__HAS_IEEE_EXCEPTIONS)
824 CALL ieee_set_halting_mode(ieee_all, halt)
832 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
835 "liwork = ", liwork, &
838 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
840 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
841 "iclustr = ", iclustr
842 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
846 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
859 a => matrix%local_data
860 IF (needs_evecs)
THEN
861 z => eigenvectors%local_data
864 z => matrix%local_data
869 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
870 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
872 lwork = max((nb + 3)*n, 8*n) + n
877 ALLOCATE (iwork(liwork))
878 ALLOCATE (work(lwork))
883 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
884 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
890 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
893 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
896 cpabort(
"Error in DSYEVX (ScaLAPACK)")
906 eigenvalues(1:neig_local) = w(1:neig_local)
909 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
911 CALL timestop(handle)
924 SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
927 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
928 REAL(kind=
dp),
DIMENSION(:),
POINTER, &
929 INTENT(INOUT) :: eigval
930 INTEGER,
INTENT(OUT),
OPTIONAL :: info
932 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_svd'
934 CHARACTER(LEN=2*default_string_length) :: message
935 INTEGER :: handle, n, m, myinfo, lwork
936 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a
938 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: work
940#if defined(__parallel)
941 INTEGER,
DIMENSION(9) :: desca, descu, descvt
943 CALL timeset(routinen, handle)
946 matrix_struct=matrix_a%matrix_struct, &
949 a => matrix_lu%local_data
950 m = matrix_lu%matrix_struct%nrow_global
951 n = matrix_lu%matrix_struct%ncol_global
960#if defined(__parallel)
962 desca(:) = matrix_lu%matrix_struct%descriptor(:)
963 descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
964 descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
967 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
968 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
970 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
971 WRITE (message,
"(A,I0,A)")
"ERROR in PDGESVD: Work space query failed (INFO = ", myinfo,
")"
972 IF (
PRESENT(info))
THEN
973 cpwarn(trim(message))
975 cpabort(trim(message))
981 ALLOCATE (work(lwork))
983 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
984 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
986 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
987 WRITE (message,
"(A,I0,A)")
"ERROR in PDGESVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
988 IF (
PRESENT(info))
THEN
989 cpwarn(trim(message))
991 cpabort(trim(message))
996 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
997 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
999 IF (myinfo /= 0)
THEN
1000 WRITE (message,
"(A,I0,A)")
"ERROR in DGESVD: Work space query failed (INFO = ", myinfo,
")"
1001 IF (
PRESENT(info))
THEN
1002 cpwarn(trim(message))
1004 cpabort(trim(message))
1009 lwork = int(work(1))
1011 ALLOCATE (work(lwork))
1014 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
1015 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
1017 IF (myinfo /= 0)
THEN
1018 WRITE (message,
"(A,I0,A)")
"ERROR in DGESVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
1019 IF (
PRESENT(info))
THEN
1020 cpwarn(trim(message))
1022 cpabort(trim(message))
1031 IF (
PRESENT(info)) info = myinfo
1033 CALL timestop(handle)
1046 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
1056 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
1057 INTEGER,
INTENT(OUT) :: n_dependent
1058 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
1059 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
1062 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
1064 INTEGER :: handle, icol_global, &
1066 ncol_global, npcol, nprow, &
1068 LOGICAL :: my_verbose
1069 REAL(kind=
dp) :: condition_number, f, p
1070 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
1071 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
1074#if defined(__parallel)
1075 INTEGER :: icol_local, ipcol, iprow, irow_global, &
1079 CALL timeset(routinen, handle)
1081 my_verbose = .false.
1082 IF (
PRESENT(verbose)) my_verbose = verbose
1084 context => matrix%matrix_struct%context
1085 myprow = context%mepos(1)
1086 mypcol = context%mepos(2)
1087 nprow = context%num_pe(1)
1088 npcol = context%num_pe(2)
1092 nrow_global = matrix%matrix_struct%nrow_global
1093 ncol_global = matrix%matrix_struct%ncol_global
1095 ALLOCATE (eigenvalues(ncol_global))
1097 eigenvalues(:) = 0.0_dp
1103 IF (
PRESENT(eigvals))
THEN
1104 eigvals(1) = eigenvalues(1)
1105 eigvals(2) = eigenvalues(ncol_global)
1108#if defined(__parallel)
1109 eigenvectors => work%local_data
1113 DO icol_global = 1, ncol_global
1115 IF (eigenvalues(icol_global) < threshold)
THEN
1117 n_dependent = n_dependent + 1
1119 ipcol = work%matrix_struct%g2p_col(icol_global)
1121 IF (mypcol == ipcol)
THEN
1122 icol_local = work%matrix_struct%g2l_col(icol_global)
1123 DO irow_global = 1, nrow_global
1124 iprow = work%matrix_struct%g2p_row(irow_global)
1125 IF (myprow == iprow)
THEN
1126 irow_local = work%matrix_struct%g2l_row(irow_global)
1127 eigenvectors(irow_local, icol_local) = 0.0_dp
1134 f = eigenvalues(icol_global)**p
1136 ipcol = work%matrix_struct%g2p_col(icol_global)
1138 IF (mypcol == ipcol)
THEN
1139 icol_local = work%matrix_struct%g2l_col(icol_global)
1140 DO irow_global = 1, nrow_global
1141 iprow = work%matrix_struct%g2p_row(irow_global)
1142 IF (myprow == iprow)
THEN
1143 irow_local = work%matrix_struct%g2l_row(irow_global)
1144 eigenvectors(irow_local, icol_local) = &
1145 f*eigenvectors(irow_local, icol_local)
1156 eigenvectors => work%local_data
1160 DO icol_global = 1, ncol_global
1162 IF (eigenvalues(icol_global) < threshold)
THEN
1164 n_dependent = n_dependent + 1
1165 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1169 f = eigenvalues(icol_global)**p
1170 eigenvectors(1:nrow_global, icol_global) = &
1171 f*eigenvectors(1:nrow_global, icol_global)
1178 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1182 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1183 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1185 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1186 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1187 "CP_FM_POWER: condition number: ", condition_number
1188 IF (eigenvalues(1) <= 0.0_dp)
THEN
1190 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1192 IF (condition_number > 1.0e12_dp)
THEN
1194 "WARNING: high condition number => possibly ill-conditioned matrix"
1198 DEALLOCATE (eigenvalues)
1200 CALL timestop(handle)
1224 TYPE(
cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1225 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1226 INTEGER,
INTENT(IN) :: start_sec_block
1227 REAL(kind=
dp),
INTENT(IN) :: thresh
1229 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1232 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1234 REAL(kind=
dp) :: tan_theta, tau, c, s
1236 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1238#if defined(__parallel)
1241 INTEGER :: myprow, mypcol, nprow, npcol, block_dim_row, block_dim_col, &
1242 info, ev_row_block_size, iam, mynumrows, mype, npe, &
1244 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1245 INTEGER,
DIMENSION(9) :: desca, descz, desc_a_block, &
1249 INTEGER,
EXTERNAL :: numroc
1254 CALL timeset(routinen, handle)
1256#if defined(__parallel)
1257 context => matrix%matrix_struct%context
1258 allgrp = matrix%matrix_struct%para_env
1260 myprow = context%mepos(1)
1261 mypcol = context%mepos(2)
1262 nprow = context%num_pe(1)
1263 npcol = context%num_pe(2)
1265 n = matrix%matrix_struct%nrow_global
1267 a => matrix%local_data
1268 desca(:) = matrix%matrix_struct%descriptor(:)
1269 ev => eigenvectors%local_data
1270 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1276 block_dim_row = start_sec_block - 1
1277 block_dim_col = n - block_dim_row
1278 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1280 mype = matrix%matrix_struct%para_env%mepos
1281 npe = matrix%matrix_struct%para_env%num_pe
1283 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1285 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1286 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1288 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1289 a_loc, 1, 1, desc_a_block, context%get_handle())
1291 CALL allgrp%bcast(a_loc, 0)
1298 ev_row_block_size = n/(nprow*npcol)
1299 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1301 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1303 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1306 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1312 DO q = start_sec_block, n
1314 DO p = 1, (start_sec_block - 1)
1316 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1318 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1320 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1323 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1331 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1332 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1333 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1334 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1335 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1343 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1346 DEALLOCATE (a_loc, ev_loc, c_ip)
1348 CALL ictxt_loc%gridexit()
1352 n = matrix%matrix_struct%nrow_global
1356 a => matrix%local_data
1357 ev => eigenvectors%local_data
1364 DO q = start_sec_block, n
1365 DO p = 1, (start_sec_block - 1)
1367 IF (abs(a(p, q)) > thresh)
THEN
1369 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1371 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1374 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1382 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1383 CALL dscal(n, c, ev(1, p), 1)
1384 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1385 CALL dscal(n, c, ev(1, q), 1)
1386 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1399 CALL timestop(handle)
1412 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1414 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1415 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1418 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1420 INTEGER :: handle, nao, nmo
1422 CALL timeset(routinen, handle)
1425 nmo =
SIZE(eigenvalues)
1445 eigenvalues=eigenvalues)
1451 CALL timestop(handle)
1467 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1468 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1470 REAL(kind=
dp),
INTENT(IN) :: epseig
1472 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1474 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1476 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: evals
1478 CALL timeset(routinen, handle)
1482 nmo =
SIZE(eigenvalues)
1483 ALLOCATE (evals(nao))
1488 evals(:) = -evals(:)
1491 IF (evals(i) < epseig)
THEN
1502 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1505 DO icol = nc + 1, nao
1511 evals(nc + 1:nao) = 1.0_dp
1514 evals(:) = 1.0_dp/sqrt(evals(:))
1517 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1518 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1521 DO icol = nc + 1, nao
1526 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1529 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1533 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 ...
subroutine, public cp_dlaf_finalize()
Finalize DLA-Future and pika runtime.
subroutine, public cp_dlaf_initialize()
Initialize DLA-Future and pika runtime.
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...