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"
83 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
92 INTEGER,
SAVE :: elpa_neigvec_min = 0
96 INTEGER,
SAVE,
PUBLIC :: dlaf_neigvec_min = 0
100 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
107#if defined(__CUSOLVERMP)
147 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
148 elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
149 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
150 LOGICAL,
INTENT(OUT) :: fallback_applied
151 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
152 LOGICAL,
INTENT(IN) :: elpa_qr, elpa_print, elpa_qr_unsafe
153 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
154 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
156 LOGICAL,
SAVE :: initialized = .false.
158 fallback_applied = .false.
160 IF (diag_lib ==
"ScaLAPACK")
THEN
162 ELSE IF (diag_lib ==
"ELPA")
THEN
169 fallback_applied = .true.
171 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
173 ELSE IF (diag_lib ==
"DLAF")
THEN
177 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
180 cpabort(
"ERROR in diag_init: Initialization of unknown diagonalization library requested")
196 dlaf_neigvec_min = dlaf_neigvec_min_input
198 mark_used(dlaf_neigvec_min_input)
201 elpa_neigvec_min = elpa_neigvec_min_input
202 eps_check_diag = eps_check_diag_input
235 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
236 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
237 INTEGER,
INTENT(OUT),
OPTIONAL :: info
239 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
244 IF (
PRESENT(info)) info = 0
247 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
250 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
252 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
258 IF (matrix%matrix_struct%nrow_global < 64)
THEN
260 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
267 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
269 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
276 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
279 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
289 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
291 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
292 INTEGER,
INTENT(IN) :: nvec
294 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
296 CHARACTER(LEN=default_string_length) :: diag_type_name
297 REAL(kind=
dp) :: eps, eps_abort, eps_warning, gold, test
298 INTEGER :: handle, i, j, ncol, nrow, output_unit
299 LOGICAL :: check_eigenvectors
300#if defined(__parallel)
302 INTEGER :: il, jl, ipcol, iprow, &
303 mypcol, myprow, npcol, nprow
304 INTEGER,
DIMENSION(9) :: desca
307 CALL timeset(routinen, handle)
311#if defined(__CHECK_DIAG)
312 check_eigenvectors = .true.
313 IF (eps_check_diag >= 0.0_dp)
THEN
314 eps_warning = eps_check_diag
317 IF (eps_check_diag >= 0.0_dp)
THEN
318 check_eigenvectors = .true.
319 eps_warning = eps_check_diag
321 check_eigenvectors = .false.
324 eps_abort = 10.0_dp*eps_warning
330 IF (check_eigenvectors)
THEN
331#if defined(__parallel)
332 nrow = eigenvectors%matrix_struct%nrow_global
333 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
334 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
335 context => matrix%matrix_struct%context
336 myprow = context%mepos(1)
337 mypcol = context%mepos(2)
338 nprow = context%num_pe(1)
339 npcol = context%num_pe(2)
340 desca(:) = matrix%matrix_struct%descriptor(:)
341 outer:
DO j = 1, ncol
343 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
344 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
345 gold = merge(0.0_dp, 1.0_dp, i .NE. j)
346 test = matrix%local_data(il, jl)
347 eps = abs(test - gold)
348 IF (eps > eps_warning)
EXIT outer
353 nrow =
SIZE(eigenvectors%local_data, 1)
354 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
355 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
356 eigenvectors%local_data(1, 1), nrow, &
357 eigenvectors%local_data(1, 1), nrow, &
358 0.0_dp, matrix%local_data(1, 1), nrow)
359 outer:
DO j = 1, ncol
361 gold = merge(0.0_dp, 1.0_dp, i .NE. j)
362 test = matrix%local_data(i, j)
363 eps = abs(test - gold)
364 IF (eps > eps_warning)
EXIT outer
368 IF (eps > eps_warning)
THEN
370 diag_type_name =
"SYEVD"
372 diag_type_name =
"ELPA"
374 diag_type_name =
"CUSOLVER"
376 diag_type_name =
"DLAF"
378 cpabort(
"Unknown diag_type")
380 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,F0.0,A,ES10.3)") &
381 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
382 "Matrix element (", i,
", ", j,
") = ", test, &
383 "The deviation from the expected value ", gold,
" is", eps
384 IF (eps > eps_abort)
THEN
385 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
387 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
392 CALL timestop(handle)
394 END SUBROUTINE check_diag
402 SUBROUTINE cp_fm_error(mesg, info, warn)
403 CHARACTER(LEN=*),
INTENT(IN) :: mesg
404 INTEGER,
INTENT(IN),
OPTIONAL :: info
405 LOGICAL,
INTENT(IN),
OPTIONAL :: warn
407 CHARACTER(LEN=2*default_string_length) :: message
410 IF (
PRESENT(info))
THEN
411 WRITE (message,
"(A,A,I0,A)") mesg,
" (INFO = ", info,
")"
413 WRITE (message,
"(A)") mesg
416 IF (
PRESENT(warn))
THEN
423 cpwarn(trim(message))
425 cpabort(trim(message))
427 END SUBROUTINE cp_fm_error
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 INTEGER :: liwork, lwork
456 INTEGER,
DIMENSION(:),
POINTER :: iwork
457 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
458 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
459 INTEGER,
TARGET :: v(1)
460 REAL(kind=
dp),
TARGET :: w(1)
463 CALL timeset(routinen, handle)
467 n = matrix%matrix_struct%nrow_global
470#if defined(__parallel)
478 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
479 IF (
PRESENT(info))
THEN
480 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
482 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
491 m => matrix%local_data
495 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
497 IF (myinfo /= 0)
THEN
498 CALL cp_fm_error(
"ERROR in DSYEVD: Work space query failed", myinfo,
PRESENT(info))
502 lwork = nint(work(1))
503 ALLOCATE (work(lwork))
506 ALLOCATE (iwork(liwork))
508 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
510 IF (myinfo /= 0)
THEN
511 CALL cp_fm_error(
"ERROR in DSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
520 IF (
PRESENT(info)) info = myinfo
522 nmo =
SIZE(eigenvalues, 1)
524 eigenvalues(1:n) = eig(1:n)
526 eigenvalues(1:nmo) = eig(1:nmo)
531 CALL check_diag(matrix, eigenvectors, n)
533 CALL timestop(handle)
544 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
546 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
547 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
548 INTEGER,
INTENT(OUT),
OPTIONAL :: info
550 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
552 INTEGER :: handle, myinfo
553#if defined(__parallel)
555 INTEGER :: liwork, lwork, n
556 INTEGER,
DIMENSION(9) :: descm, descv
557 INTEGER,
DIMENSION(:),
POINTER :: iwork
558 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
559 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
560 REAL(kind=
dp),
TARGET :: w(1)
561#if defined (__HAS_IEEE_EXCEPTIONS)
562 LOGICAL,
DIMENSION(5) :: halt
566 CALL timeset(routinen, handle)
570#if defined(__parallel)
572 n = matrix%matrix_struct%nrow_global
573 m => matrix%local_data
574 context => matrix%matrix_struct%context
575 descm(:) = matrix%matrix_struct%descriptor(:)
577 v => eigenvectors%local_data
578 descv(:) = eigenvectors%matrix_struct%descriptor(:)
580 liwork = 7*n + 8*context%num_pe(2) + 2
581 ALLOCATE (iwork(liwork))
587 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
588 work(1), lwork, iwork(1), liwork, myinfo)
590 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
591 CALL cp_fm_error(
"ERROR in PDSYEVD: Work space query failed", myinfo,
PRESENT(info))
594 lwork = nint(work(1))
595#if !defined(__SCALAPACK_NO_WA)
597 CALL pdormtr(
'L',
'U',
'N', n, n, m(1, 1), 1, 1, descm, m(1, 1), &
598 v(1, 1), 1, 1, descv, work(1), -1, myinfo)
600 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
601 CALL cp_fm_error(
"ERROR in PDORMTR: Work space query failed", myinfo,
PRESENT(info))
604 IF (lwork .LT. (work(1) + 2*n))
THEN
605 lwork = nint(work(1)) + 2*n
608 ALLOCATE (work(lwork))
611 IF (liwork .LT. iwork(1))
THEN
614 ALLOCATE (iwork(liwork))
619#if defined (__HAS_IEEE_EXCEPTIONS)
620 CALL ieee_get_halting_mode(ieee_all, halt)
621 CALL ieee_set_halting_mode(ieee_all, .false.)
624 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
625 work(1), lwork, iwork(1), liwork, myinfo)
627#if defined (__HAS_IEEE_EXCEPTIONS)
628 CALL ieee_set_halting_mode(ieee_all, halt)
630 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
631 CALL cp_fm_error(
"ERROR in PDSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
634 IF (
PRESENT(info)) info = myinfo
640 mark_used(eigenvectors)
641 mark_used(eigenvalues)
643 IF (
PRESENT(info)) info = myinfo
644 CALL cp_fm_error(
"ERROR in "//trim(routinen)// &
645 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support")
648 CALL timestop(handle)
650 END SUBROUTINE cp_fm_syevd_base
666 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
671 TYPE(
cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
672 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
673 INTEGER,
INTENT(IN),
OPTIONAL :: neig
674 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
676 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
678#if defined(__parallel)
679 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
681 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
686 CHARACTER(LEN=1) :: job_type
687 REAL(kind=
dp) :: abstol, work_syevx_local
688 INTEGER :: handle, info, liwork, lwork, &
689 m, n, nb, npcol, nprow, &
690 output_unit, neig_local
691 LOGICAL :: ionode, needs_evecs
692 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
693 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
694 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
696 REAL(kind=
dp),
EXTERNAL :: dlamch
698#if defined(__parallel)
699 INTEGER :: nn, np0, npe, nq0, nz
700 INTEGER,
DIMENSION(9) :: desca, descz
701 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
702 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
703 INTEGER,
EXTERNAL :: iceil, numroc
706 INTEGER,
EXTERNAL :: ilaenv
708#if defined (__HAS_IEEE_EXCEPTIONS)
709 LOGICAL,
DIMENSION(5) :: halt
713 n = matrix%matrix_struct%nrow_global
715 IF (
PRESENT(neig)) neig_local = neig
716 IF (neig_local == 0)
RETURN
718 CALL timeset(routinen, handle)
720 needs_evecs =
PRESENT(eigenvectors)
723 ionode = logger%para_env%is_source()
724 n = matrix%matrix_struct%nrow_global
727 work_syevx_local = 1.0_dp
728 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
731 IF (needs_evecs)
THEN
738 abstol = 2.0_dp*dlamch(
"S")
740 context => matrix%matrix_struct%context
741 nprow = context%num_pe(1)
742 npcol = context%num_pe(2)
745 eigenvalues(:) = 0.0_dp
746#if defined(__parallel)
748 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
749 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
752 a => matrix%local_data
753 desca(:) = matrix%matrix_struct%descriptor(:)
755 IF (needs_evecs)
THEN
756 z => eigenvectors%local_data
757 descz(:) = eigenvectors%matrix_struct%descriptor(:)
760 z => matrix%local_data
767 nb = matrix%matrix_struct%nrow_block
769 np0 = numroc(nn, nb, 0, 0, nprow)
770 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
772 IF (needs_evecs)
THEN
773 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
774 int(work_syevx_local*real((neig_local - 1)*n,
dp))
776 lwork = 5*n + max(5*nn, nb*(np0 + 1))
778 liwork = 6*max(n, npe + 1, 4)
782 ALLOCATE (iclustr(2*npe))
786 ALLOCATE (iwork(liwork))
787 ALLOCATE (work(lwork))
791#if defined (__HAS_IEEE_EXCEPTIONS)
792 CALL ieee_get_halting_mode(ieee_all, halt)
793 CALL ieee_set_halting_mode(ieee_all, .false.)
795 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
796 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
797#if defined (__HAS_IEEE_EXCEPTIONS)
798 CALL ieee_set_halting_mode(ieee_all, halt)
805 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
808 "liwork = ", liwork, &
811 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
813 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
814 "iclustr = ", iclustr
815 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
819 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
828 a => matrix%local_data
829 IF (needs_evecs)
THEN
830 z => eigenvectors%local_data
833 z => matrix%local_data
838 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
839 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
841 lwork = max((nb + 3)*n, 8*n) + n
846 ALLOCATE (iwork(liwork))
847 ALLOCATE (work(lwork))
854#if defined (__HAS_IEEE_EXCEPTIONS)
855 CALL ieee_get_halting_mode(ieee_all, halt)
856 CALL ieee_set_halting_mode(ieee_all, .false.)
858 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
859 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
860#if defined (__HAS_IEEE_EXCEPTIONS)
861 CALL ieee_set_halting_mode(ieee_all, halt)
867 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
870 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
873 cpabort(
"Error in DSYEVX (ScaLAPACK)")
881 eigenvalues(1:neig_local) = w(1:neig_local)
884 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
886 CALL timestop(handle)
899 SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
902 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
903 REAL(kind=
dp),
DIMENSION(:),
POINTER, &
904 INTENT(INOUT) :: eigval
905 INTEGER,
INTENT(OUT),
OPTIONAL :: info
907 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_svd'
909 INTEGER :: handle, n, m, myinfo, lwork
910 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a
912 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
913 REAL(kind=
dp),
TARGET :: w(1)
914#if defined(__parallel)
915 INTEGER,
DIMENSION(9) :: desca, descu, descvt
918 CALL timeset(routinen, handle)
921 matrix_struct=matrix_a%matrix_struct, &
924 a => matrix_lu%local_data
925 m = matrix_lu%matrix_struct%nrow_global
926 n = matrix_lu%matrix_struct%ncol_global
934#if defined(__parallel)
936 desca(:) = matrix_lu%matrix_struct%descriptor(:)
937 descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
938 descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
941 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
942 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
944 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
945 CALL cp_fm_error(
"ERROR in PDGESVD: Work space query failed", myinfo,
PRESENT(info))
948 lwork = nint(work(1))
949 ALLOCATE (work(lwork))
951 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
952 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
954 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
955 CALL cp_fm_error(
"ERROR in PDGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
959 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
960 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
962 IF (myinfo /= 0)
THEN
963 CALL cp_fm_error(
"ERROR in DGESVD: Work space query failed", myinfo,
PRESENT(info))
966 lwork = nint(work(1))
967 ALLOCATE (work(lwork))
969 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
970 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
972 IF (myinfo /= 0)
THEN
973 CALL cp_fm_error(
"ERROR in DGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
981 IF (
PRESENT(info)) info = myinfo
983 CALL timestop(handle)
996 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
1006 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
1007 INTEGER,
INTENT(OUT) :: n_dependent
1008 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
1009 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
1012 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
1014 INTEGER :: handle, icol_global, &
1016 ncol_global, nrow_global
1017 LOGICAL :: my_verbose
1018 REAL(kind=
dp) :: condition_number, f, p
1019 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
1020 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
1023#if defined(__parallel)
1024 INTEGER :: icol_local, ipcol, iprow, irow_global, irow_local
1027 CALL timeset(routinen, handle)
1029 my_verbose = .false.
1030 IF (
PRESENT(verbose)) my_verbose = verbose
1032 context => matrix%matrix_struct%context
1033 myprow = context%mepos(1)
1034 mypcol = context%mepos(2)
1038 nrow_global = matrix%matrix_struct%nrow_global
1039 ncol_global = matrix%matrix_struct%ncol_global
1041 ALLOCATE (eigenvalues(ncol_global))
1042 eigenvalues(:) = 0.0_dp
1048 IF (
PRESENT(eigvals))
THEN
1049 eigvals(1) = eigenvalues(1)
1050 eigvals(2) = eigenvalues(ncol_global)
1053#if defined(__parallel)
1054 eigenvectors => work%local_data
1058 DO icol_global = 1, ncol_global
1060 IF (eigenvalues(icol_global) < threshold)
THEN
1062 n_dependent = n_dependent + 1
1064 ipcol = work%matrix_struct%g2p_col(icol_global)
1066 IF (mypcol == ipcol)
THEN
1067 icol_local = work%matrix_struct%g2l_col(icol_global)
1068 DO irow_global = 1, nrow_global
1069 iprow = work%matrix_struct%g2p_row(irow_global)
1070 IF (myprow == iprow)
THEN
1071 irow_local = work%matrix_struct%g2l_row(irow_global)
1072 eigenvectors(irow_local, icol_local) = 0.0_dp
1079 f = eigenvalues(icol_global)**p
1081 ipcol = work%matrix_struct%g2p_col(icol_global)
1083 IF (mypcol == ipcol)
THEN
1084 icol_local = work%matrix_struct%g2l_col(icol_global)
1085 DO irow_global = 1, nrow_global
1086 iprow = work%matrix_struct%g2p_row(irow_global)
1087 IF (myprow == iprow)
THEN
1088 irow_local = work%matrix_struct%g2l_row(irow_global)
1089 eigenvectors(irow_local, icol_local) = &
1090 f*eigenvectors(irow_local, icol_local)
1101 eigenvectors => work%local_data
1105 DO icol_global = 1, ncol_global
1107 IF (eigenvalues(icol_global) < threshold)
THEN
1109 n_dependent = n_dependent + 1
1110 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1114 f = eigenvalues(icol_global)**p
1115 eigenvectors(1:nrow_global, icol_global) = &
1116 f*eigenvectors(1:nrow_global, icol_global)
1123 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1127 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1128 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1130 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1131 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1132 "CP_FM_POWER: condition number: ", condition_number
1133 IF (eigenvalues(1) <= 0.0_dp)
THEN
1135 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1137 IF (condition_number > 1.0e12_dp)
THEN
1139 "WARNING: high condition number => possibly ill-conditioned matrix"
1143 DEALLOCATE (eigenvalues)
1145 CALL timestop(handle)
1168 TYPE(
cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1169 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1170 INTEGER,
INTENT(IN) :: start_sec_block
1171 REAL(kind=
dp),
INTENT(IN) :: thresh
1173 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1176 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1178 REAL(kind=
dp) :: tan_theta, tau, c, s
1180 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1182#if defined(__parallel)
1185 INTEGER :: nprow, npcol, block_dim_row, block_dim_col, info, &
1186 ev_row_block_size, iam, mynumrows, mype, npe, q_loc
1187 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1188 INTEGER,
DIMENSION(9) :: desca, descz, &
1193 INTEGER,
EXTERNAL :: numroc
1198 CALL timeset(routinen, handle)
1200#if defined(__parallel)
1201 context => matrix%matrix_struct%context
1202 allgrp = matrix%matrix_struct%para_env
1204 nprow = context%num_pe(1)
1205 npcol = context%num_pe(2)
1207 n = matrix%matrix_struct%nrow_global
1209 a => matrix%local_data
1210 desca(:) = matrix%matrix_struct%descriptor(:)
1211 ev => eigenvectors%local_data
1212 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1218 block_dim_row = start_sec_block - 1
1219 block_dim_col = n - block_dim_row
1220 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1222 mype = matrix%matrix_struct%para_env%mepos
1223 npe = matrix%matrix_struct%para_env%num_pe
1225 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1227 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1228 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1230 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1231 a_loc, 1, 1, desc_a_block, context%get_handle())
1233 CALL allgrp%bcast(a_loc, 0)
1240 ev_row_block_size = n/(nprow*npcol)
1241 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1243 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1245 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1248 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1254 DO q = start_sec_block, n
1256 DO p = 1, (start_sec_block - 1)
1258 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1260 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1262 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1265 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1273 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1274 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1275 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1276 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1277 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1285 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1288 DEALLOCATE (a_loc, ev_loc, c_ip)
1290 CALL ictxt_loc%gridexit()
1294 n = matrix%matrix_struct%nrow_global
1298 a => matrix%local_data
1299 ev => eigenvectors%local_data
1306 DO q = start_sec_block, n
1307 DO p = 1, (start_sec_block - 1)
1309 IF (abs(a(p, q)) > thresh)
THEN
1311 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1313 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1316 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1324 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1325 CALL dscal(n, c, ev(1, p), 1)
1326 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1327 CALL dscal(n, c, ev(1, q), 1)
1328 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1341 CALL timestop(handle)
1354 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1356 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1357 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1360 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1362 INTEGER :: handle, nao, nmo
1364 CALL timeset(routinen, handle)
1367 nmo =
SIZE(eigenvalues)
1387 eigenvalues=eigenvalues)
1393 CALL timestop(handle)
1409 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1410 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1412 REAL(kind=
dp),
INTENT(IN) :: epseig
1414 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1416 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1418 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: evals
1420 CALL timeset(routinen, handle)
1424 nmo =
SIZE(eigenvalues)
1425 ALLOCATE (evals(nao))
1430 evals(:) = -evals(:)
1433 IF (evals(i) < epseig)
THEN
1444 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1447 DO icol = nc + 1, nao
1453 evals(nc + 1:nao) = 1.0_dp
1456 evals(:) = 1.0_dp/sqrt(evals(:))
1459 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1460 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1463 DO icol = nc + 1, nao
1468 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1471 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1475 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...